Serial.flush werkt niet, wat is het alternatief?

Heb weinig ervaring met het programmeren in Arduino en ben met mijn eerste project bezig.

Het betreft een project om data van een enkele I/O-lijn (= 1 verbinding voor zowel zenden als ontvangen) met een ESP-01-module (accesspoint) via TCP te verzenden naar een andere ESP-01-module (client), waarna daar weer een I/O-lijn uit komt.

Omdat de I/O-lijn uit 1 verbinding voor zowel het verzenden als ontvangen bestaat en de ESP-modules een aparte in- en output hebben voor de RX en TX zijn de RX en TX via een level-shifter met elkaar verbonden.

Maar nu komt het probleem.
Als de ESP-module de data in de TX-buffer via de TX-pin eruit gooit gaat deze data naar de I/O-lijn (dat is dus goed) maar wordt deze data ook via de RX-pin meteen weer teruggestuurd en dat is niet de bedoeling.

Omdat de RX en TX van beide ESP-01-module's op dezelfde manier met elkaar verbonden zijn blijft de data dus de hele tijd rondzingen.

Ik ben op zoek naar een manier om de RX-buffer leeg te maken vlak nadat de TX-buffer de data eruit gegooid heeft.

Heb begrepen dat dit voorheen met serial.flush werd gedaan maar dat dit niet meer werkt.

Ben al dagen lang op internet aan het zoeken, heb van alles geprobeerd maar heb niets gevonden wat werkt.

Wie kan mij vertellen hoe ik de RX-buffer kan leegmaken?

Serial.flush() deed vroeger iets anders dan tegenwoordig en misschien doet het niets. Dat is voor de Arduino boards, wat het op een ESP8266 doet is misschien weer iets anders.

Als je de RX niet kunt disablen, dan kun je de buffer leegmaken:

while( Serial.available() > 0)
{
  Serial.read();  // read it and throw it away.
}

Heb je wel eens aan een ESP32 gedacht ?

Bedankt voor de snelle reactie!

Denk dat ik nog even wat extra informatie moet geven.

De data die uit de TX-pin komt betreft een vraag aan het apparaat wat aan de I/O-lijn hangt, het apparaat wat aan de I/O-lijn hangt geeft meteen na het ontvangen van de vraag een antwoord terug.

De vraag wil ik dus niet via de RX-pin naar de andere ESP-module terugsturen maar het antwoord wel.

Dus ik dacht zelf aan: vraag uit TX-pin => wis RX-buffer (om de vraag in de RX-buffer te wissen) => antwoord via RX-pin in RX-buffer laden en verzenden naar TCP.

Hier het stukje code:
// Read data from the connected client and write it to the serial-port (TCP => UART)
while(client.available() > 0){
Serial.write(client.read()); //(write TX-buffer (client) to UART (I/O-line))
}

// Read data from serial-port and send it to the connected client (UART => TCP)
while(Serial.available() > 0){
client.write(Serial.read()); //(write RX-buffer (client) from UART (I/O-line) to TCP)
}

Wat moet hier veranderd aan worden om het werkend te krijgen zoals hierboven beschreven?

Het leek een eenvoudige vraag, maar nu wordt het opeens erg lastig :o

Nu hangt er maar van af wat de baudrate is, hoe snel het gaat, hoe snel er gereageerd wordt, hoe groot de data is die van de TCP verbinding komt, of de data via TCP uit één afgerond blok data bestaat en hoe groot de seriële RX buffer is. In het verleden zat er een fout in een library waardoor per TCP transfer slechts één byte werd meegegeven. Met zo iets loopt deze situatie al snel in de soep.

Die while-loops kunnen voor vertraging zorgen. Soms is het beter om maar één byte per Arduino loop() te doen.

Als er meteen een antwoord komt, dan kun je niet zomaar onderscheid meer maken tussen wat je zelf hebt verstuurd en wat er nieuw wordt ontvangen.

Ik kan drie oplossingen uit mijn mouw schudden, misschien weten anderen nog andere oplossingen:

  1. Je kunt een byte versturen, dan wachten totdat je datzelfde byte hebt ontvangen en dat uit de buffer halen. Dan gaat het niet meer op volle snelheid. Dit heeft een paar risico's als er storing is of als er een synchronisatieprobleem ontstaat.
  2. Als de gegevens die via TCP binnenkomen een duidelijke afsluiter hebben (carriage return of linefeed), dan kun je de gegevens weggooien tot en met die afsluiter. Dat is een nette manier.
  3. Je kunt tellen hoeveel bytes je verstuurd en die eerst weglezen. Dit heeft veel risico's.

Nummer 3) zou er zo uit kunnen zien:

// empty the serial RX buffer, to keep TX and RX are the same amount of bytes.
while( Serial.available() > 0)
{
  Serial.read();
}

// Send bytes, remember how many bytes.
// The buffer should not overflow, because then there will be a mismatch between RX and TX bytes.
// Read data from the connected client and write it to the serial-port (TCP => UART)
int count = 0;
while( client.available() > 0)
{
  Serial.write( client.read());   // (write TX-buffer (client) to UART (I/O-line))
  count++;
}

// Remove the number of bytes that were send
for( int i=0; i<count; i++)
{
  Serial.read();
}

// The rest is real data from the other device
// Read data from serial-port and send it to the connected client (UART => TCP)
// When that device is slow or the code is fast, it might not have arrived yet. A extra timeout would be better.
while( Serial.available() > 0)
{
  client.write( Serial.read()); //(write RX-buffer (client) from UART (I/O-line) to TCP)
}

Er zijn nogal wat manieren waarop dit fout kan kan.
Als er data naar het seriële apparaat wordt verstuurd, en die data is verdeeld over twee TCP blokken, dan gaat het al fout.

De baudrate is 9600 baud.

De "vragen" en "antwoorden" hebben niet een vaste lengte, kan kort zijn of lang zijn.
Nadat de vraag gesteld is komt het antwoord er vrijwel meteen achteraan.

Dus als ik via de ene ESP-module een vraag verstuur dan krijg in deze vraag meteen retour met het antwoord er achteraan.

Omdat bij beide ESP-modules de RX en TX met een level-shifter aan elkaar zitten blijft de data rondzingen.
Dus data wat in de RX-pin van ESP1 gaat komt er uit de TX-pin van ESP2 uit, gaat in de RX-pin van ESP2 er weer in en komt er uit de TX-pin van ESP1 weer uit waarna deze weer in de RX-pin van ESP1 gaat, enz.

Toen ik dit in Arduino wilde maken ging ik er vanuit dat daar wel een oplossing voor zou zijn maar zoals ik het nu bekijk valt dat een beetje tegen.

Je zou toch verwachten dat er toch wel een simpele manier moet zijn om een buffer te wissen.

Ben nu nog aan het kijken of ik de RX-pin niet hardwarematig met een MOSFET of transistor van de I/O-line los kan koppelen, heb nog een I/O-pin over waarmee ik op een bepaald punt de RX-pin mee in kan schakelen.

Dat zou er dan zo uit moeten zien:
// Read data from the connected client and write it to the serial-port (TCP => UART)
while(client.available()){
digitalWrite(GPIO2, HIGH); // Disable RX-input
Serial.write(client.read()); // Write TX-buffer (client) to UART
}

// Read data from serial-port and send it to the connected client (UART => TCP)
while(Serial.available()){
digitalWrite(GPIO2, LOW); // Enable RX-input
client.write(Serial.read()); // Write RX-buffer (client) to TCP
}

Maar als het softwarematig opgelost kan worden dan heb ik dat liever, kan ik die I/O-pin nog ergens anders voor gebruiken.

Ik heb drie software-oplossingen gegeven die alle drie werken en waarvan ik er eentje helemaal het uitgewerkt met commentaar waar je op moet letten.

Misschien kun je een schema geven en de complete sketch van beide ESP modules en het formaat van de gegevens die verstuurd en ontvangen worden.

Het probleem is dat je (net als anderen) moeilijk gaat doen en steeds meer hardware gaat toevoegen om zo'n ESP-01 te blijven gebruiken. Je kunt ook een ESP32 nemen en dan ben je van alle problemen verlost :smiley:
Als ik zo iets schrijf dan krijg ik als reactie dat het een leuk leertraject is, maar je kunt beter je tijd in de werking van ESP32 steken, daar heb je echt iets aan.

Als de lengte van de data variabel is, dan is er een soort van afsluiter neem ik aan. Hoe weet anders de ontvangende kant dat de hele data is ontvangen en dat hij iets terug moet gaan sturen ?
Als er een afsluiter is, dan is mogelijkheid 2) de beste oplossing.

Ga er eerdaags mee verder met de door jouw opgegeven mogelijkheden.

De ESP-01 is qua afmetingen precies goed en zou voldoende mogelijkheden moeten hebben om de klus te klaren.
Mocht er softwarematig geen oplossing voor zijn en ik het met een kleine hardwarematige ingreep toch werkend krijgen dan vind ik dat prima.

Een ESP32 is qua afmeting groter en uitgebreider.

Zie net dat ik het niet helemaal goed verteld heb.

Bij 90% van de vragen is het antwoord telkens hetzelfde.

Deze 90% van de vragen/antwoorden is de lengte verschillend.
Een vraag kan 6 bytes lang zijn en het antwoord 12 bytes.
Een vraag kan 10 bytes lang zijn en het antwoord 20 bytes.

Van 10% van de "vragen" is het antwoord verschillend maar wel hetzelfde aantal bytes.
Dit zijn datapakketten van 64 bytes.

Als het apparaat aan de ene kant een vraag stelt weet deze precies hoeveel bytes hij terug moet krijgen om naar de volgende stap te gaan.

Is de eerste byte een soort van identifier is die bepaald of het 6 of 10 bytes is ?
Dus je wilt alle bytes heen een weer laten gaan, en die echo er uit halen.
Dan is mogelijke 1) veiliger, maar dan kan er nog steeds iets mis gaan. Dan is er allerlei code nodig om uitzonderingen en storing op te vangen met timeouts, enzovoorts.

Dus het kan wel, maar je zoekt problemen op en die krijg je dan ook :wink:

je kunt de pin overal waar nodig even uitzetten, bijvoorbeeld door er een uitgang van te maken, dat werkt hetzelfde als dat je er een mosfet tussenplakt, echter als je de pin weer op ingang zet dan kan het zijn dat de buffer over de zeik gaat, dat weet ik niet. in 9600 baud heb je trouwens veel rekensnelheid over dus het kan ook in software.

Om even een beeld te schetsen van de data, zie onderstaande link van hoe de data eruit ziet:

Ik wil inderdaad de bytes heen en weer laten gaan zonder de echo.