Serial.flush() doesn't work as I expected it to

Firstly, I need to mention that I am using Strings because I am on an ESP32 and it makes my life so much easier.

I have written a piece of code that sends a command to an RFID reader and then reads a part of the incoming data.
Please note that the send command routine is basic and won't be used in a real working environment. Not in this form anyway.

 //  outside of void loop()
 bool command = true;

  // RFID routine
  if (activateRFID)
  {
    // send command to reader
    if (command)
    {
      Serial1.print("mt2000\r"); // set read interval
      command = false; // so that this code executes only once
      // delay(500);
      // Serial1.flush();
// read incoming data from the sent command
      if (Serial1.available() > 10)
      {
        String str = Serial1.readStringUntil((char)'>');
        Serial.println(str);
      }
      // delay(2000);
      // Serial1.flush();
    }

    String rf_id;

// read incoming data from a RFID card read at some point in time
    if (Serial1.available() > 10)
    {
      Serial.println();
      Serial.print("Before: ");
      Serial.println(Serial1.available()); // number of bytes available to read
      char input[9];

      String str = Serial1.readStringUntil((char)'B');
      Serial.println(str);
      Serial1.flush();
    }
  }

My purpose is to send the command then read part of the incoming data(first if(Serial1.available() > 10)) then "flush" the rest of that respective data so that the serial buffer is empty so that it can be ready for the next incoming piece of data(second if(Serial1.available() > 10)).

The problem is that I can't figure out a way of "flushing" the extra data before the second if (Serial1.available() > 10).

I've tried using Serial1.flush() in the places that it is commented in the code above, but this doesn't discard the buffer. In both cases this adds the data from the command to the data that's coming when I read a RFID card.
I've also tried other methods that I've found on this forum, like:

while(Serial1.available())
{
  char t = Serial1.read();
}

And it still enters in the second if (Serial1.available() > 10).

Using delay(500) and using it only before the first if (Serial1.available() > 10) is the only way to ensure that the second if (Serial1.available() > 10) isn't true.

I am trying to understand this because in a normal working environment the reader can read card after card and I don't want the incoming data from the first read to add to the second read and so on. That's why there is a Serial1.flush(); at the end of the code.

If I remove that Serial1.flush(); the code enters the second if twice and the second time Serial.println(str); prints the rest of the data that came from reading a card. I think that this Serial1.flush(); does something useful but only because the default serial timeout is 1000ms and the RFID reader is set to read cards at a 2000ms interval.

The more I dig in the less I understand.

Here is the description of what Serial.flush does from the Arduino Reference page:

Waits for the transmission of outgoing serial data to complete

I agree that the name doesn't really match it's function.

The problem is that I can't figure out a way of "flushing" the extra data

A simplewhile (Serial1.available()) if (Serial1.read());should do the trick.

I agree that the name doesn't really match it's function.

The function of flush() was changed in the 1.x core from what you expected to what it is now.

Deva_Rishi:
A simple

while (Serial1.available()) if (Serial1.read());

should do the trick.

I don't think there should be an IF in that. I do it like this

while (Serial1.available()) {
   Serial1.read();
}

...R

EDIT to change the IF in my example to WHILE - apologies for any confusion that may have caused

You can empty the serial buffer by executing Serial1.read() commands until Serial1.available() is 0, but that gives you the problem that serial input is so slow that your code will see the empty buffer between characters as they are still being received. If your code is not doing anything that takes a significant amount of time, it is unlikely you will ever see more than 11 characters (as detected by Serial1.available() > 10) in the input buffer at any given time, so the flush would not work anyway.

What format is the serial input data? Is there a specific character, such as a newline or carriage return, that indicate the end of a line of data?

What is the format of the data?
My SafeString library has a Reader class with a skipToDelimiter() function
see the Reading User Commands part of the Text I/O for the Real World

So once you have read the initial part, you call sfReader.skipToDelimiter(); and the SafeString Reader will skip over (flush) the rest of the input until it reaches the next delimiter and starts reading again. You can set what ever delimiters (one or more) that you like.

All the SafeString methods are non-blocking, unlike the readStringUntil method you are using at the moment

p.s. The SafeString Reader also has a non-blocking timeout option if you don't have a delimiter.

Here is a non-blocking String version based on a timeout

#include <millisDelay.h>
// see the tutorial https://www.forward.com.au/pfod/ArduinoProgramming/TimingDelaysInArduino.html
// millisDelay is included in the SafeString library available form the library manager

String strInput;
unsigned int strInput_RESERVE = 100; // say allow for 100 char input
millisDelay flushTimeOut;
unsigned long FLUSH_TIMEOUT_MS = 100; // say 0.1 sec

// returns true until no more chars for 0.1 sec
bool clearInput() {
  while (Serial.available()) {
    Serial.read();
    flushTimeOut.start(FLUSH_TIMEOUT_MS);
  }
  if (flushTimeOut.justFinished()) {
    return false;
  }
  return true; // keep clearingInput
}

// stopC is the char to stop at
// returns true when get stopC and input contains the input up to then
// else return false
bool readStrUntil(char stopC, String& input) {
  while (Serial.available()) {
    char c = Serial.read();
    if (c == stopC) {
      return true; // input has char upto stopC
    }
    // else
    input += c;
    if (input.length() >= strInput_RESERVE) {
      // prevent re-allocation and fragmenation
      return true; // input has char upto stopC
    }
  }
  return false;
}

void setup() {
  Serial.begin(9600);
  for (int i = 10; i > 0; i--) {
    Serial.print(i); Serial.print(' ');
    delay(500);
  }
  Serial.println();
  strInput.reserve(strInput_RESERVE); // to prevent fragmenation
  while (clearInput()) { }; // clear out Serial to start with
  Serial.println(F(" Serial input has been cleared. Ready for input"));
}

bool clearingInput = false;
bool readingB = false;

void loop() {
  if (clearingInput) {
    clearingInput = clearInput(); // returns false when input flushed on timeout
  }

  if ((!clearingInput) && (!readingB)) {
    if (readStrUntil('>', strInput)) {
      Serial.println(F(" found >"));
      Serial.println(strInput);
      // process input here
      strInput = ""; // clear for next input after processing
      clearingInput = true;
      readingB = true;
    }
  }

  if ((!clearingInput) && (readingB)) {
    if (readStrUntil('B', strInput)) {
      Serial.println(F(" found B"));
      Serial.println(strInput);
      // process input here
      strInput = ""; // clear for next input after processing
      clearingInput = true;
      readingB = false;
    }
  }
}

The following code:

if(Serial1.available()) {
  Serial.print(Serial1.read());
  Serial.print(" ");
}

outputs this when I read a card:

0 0 91 61 25 160 128 0 0 0 0 0 0 0 0 0 0 118 118 54 16 18 32 1 1 1 1 1 0 0 248 126 118 55 50 162 129 32 0 1 1 1 0 0 0 119 247 38 33 17 1 9 128 0 1 0 0 0 55 103 39 1 17 9 32 0 0 0 0 255 255 119 55 49 34 34 128 128 1 1 1 0 0 126 119 103 51 17 25 25 128 1 1 0 0 0 118 54 38 38 32 1 1 1 1 1 1 0 0 0 55 50 54 50 2 128 128 1 1 1 1 0 0 126 54 50 162 130 129 32 1 0 1 0 0 0 255 119 118 55 54 25 25 128 1 1 1 0 127 255 126 118 102 39 35 1 9 1 0 0 1 0 0 126 254 54 54 51 38 1 17 17 9 0 0 0 118 118 16 35 33 1 9 32 0 0 1 0 55 54 54 16 34 1 1 1 1 1 1 0 118 55 54 38 33 1 1 9 0 0 0 0 0 254 118 118 18 34 34 1 1 1 1 0 0 0 55 54 50 34 130 1 1 1 9 1 0 0 126 55 54 35 1 25 9 0 1 0 0 0 0 0 0 0 136 119 54 50 36 32 1 1 1 1 0 0 0 0 119 54 55 51 25 25 32 1 1 1 1 0 0 119 103 51 51 17 25 32 0 1 1 0 0 0 0 255 54 54 54 39 17 17 25 32 0 1 0 1 0 0 0 127 183 55 16 38 33 1 1 1 0 1 0 0 0 0 254 118 103 55 51 54 16 32 33 1 1 1 1 0 248 55 55 118 52 103 35 1 17 9 1 0 255 118 63 25 54 9 0 1 0 0 1 0 55 118 55 35 17 25 32 0 1 0 9 1 1 0 0 0 0 127 118 54 51 49 17 9 0 1 1 1 0 0 252 118 118 55 55 35 33 17 9 0 0 0 119 183 54 39 33 25 25 0 0 1 0 118 119 54 54 35 49 1 9 0 0 0 0 0 0 55 54 54 33 17 9 9 128 0 0 0 118 39 33 25 25 0 128 0 0 0 0 255 55 54 18 36 33 1 1 1 0 0 0 0 0 0 119 55 54 33 17 17 9 128 0 0 0 55 54 50 36 37 1 17 1 1 1 1 0 0 0 0 0 126 55 50 102 36 33 1 1 1 1 0 0 247 118 54 54 16 32 32 1 1 1 0 0 55 116 18 38 33 1 1 1 1 0 0 126 114 102 38 33 1 1 1 0 0 0 0 127 118 114 39 33 1 17 9 0 1 0 0 1 0 118 114 39 35 1 1 9 0 0 0 1 0 1 0 55 16 38 32 1 1 1 1 0 0 114 50 33 33 1 9 9 0 0 0 0 118 50 39 54 33 1 17 9

Since it has no delay it will read forever.

The sequence that repeats is:

013 010
045 065 065 048 052 070 048 050 067
013 010
069 082 082 058 048 120 049 052
013 010
062

Which translates to:

-AA04F02C
ERR:0x14
>

All I'm really interested in is 065 065 048 052 070 048 050 067 which is AA04F02C.

So the data format is ASCII ?

0 0 91 61 25 160 128 0 0 0 0 0 0 0 0 0 0

Those 0's will be a problem for Strings (and SafeStrings), they will terminate the string buffer
looks like you need to use byte[] instead

I don't think there should be an IF in that.

Technically speaking Serial.read() always returns a byte, so i tend to show that i am calling a 'non-void' function by pretending to execute a conditional bit of code (just ';' in this case) I am confident that the compiler optimizes the result to the same thing.

All I'm really interested in is 065 065 048 052 070 048 050 067 which is AA04F02C.

That would be an ascii representation of it.

So the data format is ASCII ?

The data format on the receiving end is 'byte', but just from looking at it i would say the data that is being send is a Hexdecimal value, represented in ascii. This can be helpful, that would mean you can discard anything that is not within that range (0-9 & A-F) Mind you, this is just from looking at it.

Deva_Rishi:
Technically speaking Serial.read() always returns a byte,

Serial.read() returns an int, and will return -1 if the serial buffer was empty.

GeorgeFlorian:
The following code:

if(Serial1.available()) {

Serial.print(Serial1.read());
 Serial.print(" ");
}




outputs this when I read a card:


0 0 91 61 25 160 128 0 0 0 0 0 0 0 0 0 0 118 118 54 16 18 32 1 1 1 1 1 0 0 248 126 118 55 50 162 129 32 0 1 1 1 0 0 0 119 247 38 33 17 1 9 128 0 1 0 0 0 55 103 39 1 17 9 32 0 0 0 0 255 255 119 55 49 34 34 128 128 1 1 1 0 0 126 119 103 51 17 25 25 128 1 1 0 0 0 118 54 38 38 32 1 1 1 1 1 1 0 0 0 55 50 54 50 2 128 128 1 1 1 1 0 0 126 54 50 162 130 129 32 1 0 1 0 0 0 255 119 118 55 54 25 25 128 1 1 1 0 127 255 126 118 102 39 35 1 9 1 0 0 1 0 0 126 254 54 54 51 38 1 17 17 9 0 0 0 118 118 16 35 33 1 9 32 0 0 1 0 55 54 54 16 34 1 1 1 1 1 1 0 118 55 54 38 33 1 1 9 0 0 0 0 0 254 118 118 18 34 34 1 1 1 1 0 0 0 55 54 50 34 130 1 1 1 9 1 0 0 126 55 54 35 1 25 9 0 1 0 0 0 0 0 0 0 136 119 54 50 36 32 1 1 1 1 0 0 0 0 119 54 55 51 25 25 32 1 1 1 1 0 0 119 103 51 51 17 25 32 0 1 1 0 0 0 0 255 54 54 54 39 17 17 25 32 0 1 0 1 0 0 0 127 183 55 16 38 33 1 1 1 0 1 0 0 0 0 254 118 103 55 51 54 16 32 33 1 1 1 1 0 248 55 55 118 52 103 35 1 17 9 1 0 255 118 63 25 54 9 0 1 0 0 1 0 55 118 55 35 17 25 32 0 1 0 9 1 1 0 0 0 0 127 118 54 51 49 17 9 0 1 1 1 0 0 252 118 118 55 55 35 33 17 9 0 0 0 119 183 54 39 33 25 25 0 0 1 0 118 119 54 54 35 49 1 9 0 0 0 0 0 0 55 54 54 33 17 9 9 128 0 0 0 118 39 33 25 25 0 128 0 0 0 0 255 55 54 18 36 33 1 1 1 0 0 0 0 0 0 119 55 54 33 17 17 9 128 0 0 0 55 54 50 36 37 1 17 1 1 1 1 0 0 0 0 0 126 55 50 102 36 33 1 1 1 1 0 0 247 118 54 54 16 32 32 1 1 1 0 0 55 116 18 38 33 1 1 1 1 0 0 126 114 102 38 33 1 1 1 0 0 0 0 127 118 114 39 33 1 17 9 0 1 0 0 1 0 118 114 39 35 1 1 9 0 0 0 1 0 1 0 55 16 38 32 1 1 1 1 0 0 114 50 33 33 1 9 9 0 0 0 0 118 50 39 54 33 1 17 9

If you read the same card twice, does the new data get added to the end of the same line in the serial monitor, or does it appear on a separate line?

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.