Go Down

Topic: SoftwareSerial::flush() broken (Read 4732 times) previous topic - next topic

TrickyT

There's a bug in the 1.0.1 version of the SoftwareSerial flush() method.

The action for flush() changed in Arduino 1.0.  It now waits for the transmission of outgoing serial data to complete.  (Prior to 1.0, flush() instead removed any buffered incoming serial data.)  It works correctly for hardware serial I/O, but someone forgot to change this behavior for SoftwareSerial, so it still behaves the old way and deletes any previously buffered received characters and doesn't care anything about the characters being transmitted.

So if your code does something like this:

//Make sure TX has completed
    mySerial.flush();

...it's not going to work as expected.

fat16lib

#1
Jul 31, 2012, 04:08 pm Last Edit: Jul 31, 2012, 04:10 pm by fat16lib Reason: 1
Yes, flush() in SoftwareSerial still clears input.

The good news is you don't need it for output since output is not buffered in SoftwareSerial.

The bad news was that the functionality of flush was changed by the Arduino group instead of defining a new function.

Gradually libraries and programs are being fixed after this gratuitous change.  Maybe someday they will fix SoftwareSerial.

fat16lib

#2
Jul 31, 2012, 04:58 pm Last Edit: Jul 31, 2012, 05:04 pm by fat16lib Reason: 1
Other bad news about flush().  HardwareSerial flush of output doesn't work correctly either.  The documentations says:
Quote

flush()
Description

Waits for the transmission of outgoing serial data to complete.


It only waits for the SRAM buffer to be empty.  There may be two characters that have not been sent, one in the shift register and one in the UART data buffer.

If you call Serial.end() after flush(), these characters will be lost or garbled. Anything that resets the UART or changes the UART will lose these characters.  

This can kill protocols where you send at various speeds.  To set the speed of a SiRF GPS you send a message at every baud rate that tells it what baud rate you want to use.

Paul Stoffregen

Quote

HardwareSerial flush of output doesn't work correctly either.


This is issue 871

http://code.google.com/p/arduino/issues/detail?id=871

matelot

Jermy Blum on his website offers a program

Code: [Select]
//Program by Jeremy Blum
//www.jeremyblum.com
//Uses commands from computer to control arduino

int ledPin = 13;

void setup()
{
  //Create Serial Object
  Serial.begin(9600);
 
  pinMode(ledPin, OUTPUT);
}

void loop()
{
  //Have the arduino wait to receive input
  while (Serial.available() == 0);
 
  //Read the Input
  int val = Serial.read() - '0';
 
  if (val == 1)
  {
    Serial.println("Led is On");
    digitalWrite(ledPin, HIGH);
  }
  else if (val == 0)
  {
    Serial.println("Led is Off");
    digitalWrite(ledPin, LOW);
  }
  else
  {
    Serial.println("Invalid!");
  }
  Serial.flush();
 
 

This allows instructions to be printed but if more than one key is pressed the Serial.flush(); is supposed to remove all but the first key press. It fails on version 1.0.
A few people have been asking on his site if there has been an alternative way of solving this but no-one has come up with one.
Does anyone here know how?
Matelot.

fat16lib

I believe pre 1.0 flush() discarded all characters in the input buffer.

I think most people use something like this:
Code: [Select]
  while (Serial.read() >= 0) {}

If you want to discard all but n characters you could do this:
Code: [Select]
while (Serial.available() > n) Serial.read();

For n == 0 this is like the old flush().

I understand the Arduino group is thinking of bringing back the old flush with a new name.  Way to go team!

Paul Stoffregen

Actually, I've been thinking about it, since someone recently made a compelling case for efficiently discarding unnecessary protocol stuff from a certain wifi-to-serial adaptor.

I created a patch, but haven't had time to throughly test it yet.

The name will be Serial.clear(), because Arduino generally follows Processing's naming conventions.

WizenedEE


Actually, I've been thinking about it, since someone recently made a compelling case for efficiently discarding unnecessary protocol stuff from a certain wifi-to-serial adaptor.

I created a patch, but haven't had time to throughly test it yet.

The name will be Serial.clear(), because Arduino generally follows Processing's naming conventions.


I'm not sure if you're the best one to ask, but it would be nice if it accepted an optional argument that says how many bytes to discard.

Useful for when your protocol states that a transaction will always be (say) 10 bytes with the first being what kind of message it is -- if a message only needs to be 4 bytes, you'll want to discard the other 6. Or if you receive a message from a GPS unit telling you the time, you may want to just ignore it and throw away several bytes.

I don't think a method that does the same as the old flush will be as helpful though, since it's possible the next message has started and you accidentally throw away it also.

fat16lib

Maybe some of the Stream functions would work http://arduino.cc/en/Reference/Stream.  You can skip bytes using these functions.

You are really talking about parsing an input stream. At this level I write my own functions.  In fact I wrote a replacement for HardwareSerial for my personal use.

bperrybap


Actually, I've been thinking about it, since someone recently made a compelling case for efficiently discarding unnecessary protocol stuff from a certain wifi-to-serial adaptor.

I created a patch, but haven't had time to throughly test it yet.

The name will be Serial.clear(), because Arduino generally follows Processing's naming conventions.


It so hurts me to keep seeing new terms being used to define "new" functionality
when it suddenly becomes obvious again that some of that old functionality really was needed.
In this case, technically, I guess the IOSTREAM library guys and processing have created the problems here.

My preference would be that if
names are to be changed/updated how about we use the names and meanings
that were always historically used in serial devices?

flush() means discard,
drain() means wait for things to empty.

It had been that way for decades - long before the stream i/o guys
incorrectly picked the term "flush" to mean to drain out queued data.
and long before APIs like Win32 which now use the term "purge" to flush out buffers.
(Although I think "purge" is more intuitive than "flush" as to what it really does)

It used to be so simple and consistent.

For those too young to remember: here is some information on the topic:
http://www.serialio.com/support/jspUsing.htm

But I guess I can only dream.....

---- bill


Go Up