Serial.readBytes() question

Forgive my ignorance on this one - but what is the most effective design pattern for buffering serial data on the arduino? It seems most of the sample code reads a byte at a time, where I thought it would be more effective to use readBytes() to read in the available data at once and then store it in a buffer. But it would seem readBytes() doesn’t take a start position, making it difficult to be practical for buffering incoming data (unless I’m missing something basic here).

For example, most of the code I’ve seen does something along the lines of:

int bytes=Serial.available();
for(int i=startPosition;i<startPosition+bytes;i++){
  buffer[i]=Serial.read();
  // parse buffer for your string/command
}

I thought it would be more efficient to do:

int bytes=Serial.available();
Serial.readBytes(buffer, startPosition, bytes); // of course this won't work, but neither does Serial.readBytes(&buffer+startPosition, bytes);
// parse buffer for your string/command

Of course, readBytes doesn’t take a start position, it will write to the start of your buffer. I was hoping some quick pointer math would allow me to set the buffer start position, but that doesn’t compile on the arduino.

The reason I’m even concerned over this is I have some critical timing code and am trying to reduce any loops, especially when data is coming in at a high rate. Ideas? Or am I missing something simple here? :~

Why post twice? That's not effective.

I actually have no idea what happened there.. browser error!

Well pointer math does solve this.. I'm just rusty - it would be *, not &. I'll see myself out now. :fearful:

int bytes=Serial.available();
*buffer += startPosition;
Serial.readBytes(buffer, bytes);

Though if anyone wants to suggest that this isn't the best way to buffer input data, please feel free to enlighten me.

Hey mike, do u think Serial.readBytes() will read the current bytes not the previously availabe bytes in the serial? i have a problem reading the bytes in my serial monitor. the Serial.read() reads the bytes that were previously logged in the serial. so when first process takes place, it returns null because the serial is initially null. then for the second process, it will return the output for first process. and so on for the next processes. sorry for an out of the topic reply.

the Serial.readBytes() function I am looking at, takes only 2 parameters.

possible variation?

int bytes=Serial.available();
Serial.readBytes( &buffer[startposition], bytes); // you can use the address of an indexed element
startposition += bytes;

replaysMike, I am uncertain that readBytes() is likely to be a “more efficient way”.

I assume that the readBytes() mehtod of the Serial object is inherited from the Stream class and looks like this

size_t Stream::readBytes(char *buffer, size_t length)
{
  size_t count = 0;
  while (count < length) {
    int c = timedRead();
    if (c < 0) break;
    *buffer++ = (char)c;
    count++;
  }
  return count;
}

in short it seems to be of no advantage to use readBytes there is non memcpy (see memcpy - C++ Reference) like thing happening that would improve the speed.

Either way read() or readBytes() there will be steps of reading the bytes one-by-one.
There is even the overhead of the timedRead()-functions to consider in case of readBytes()… so I woudl actually think you might render your code unintentionally even slower.

I assume the choice for readBytes() is rather a “shurtcut” if you do not want to make “time-out()” way of reading the bytes youself… and of course to safe for having to write the for(;:wink: or while() loop etc etc.

Consider also that readBytes() is blocking, while a “selfmade” for(;;){…; Serial.read();…} could use the time “waiting for new input” to already do some other task).

MOst likely (if efficiency is your goal) you can gladly stick to the good-ole+plain Serial.read() function.

I am happy for feedback of somebody to “back up” or “critic” or complete my statements and suggestions!

Alexander,

A+! I hadn't actually looked at the source for readBytes(), and maybe that should have been my starting point. I wasn't aware that it was using timedRead() as well as a loop, figured it was going to be doing a block copy from it's internal buffer. It would definitely be more advantageous to do the standard Serial.read() and let my runtime loop handle the data as it comes in. This way I'm not blocking any mission critical timing.

Thanks for making it clear!

I don't like all those fancy "do everything for you, don't you worry about that" function calls.

Doing it the basic way, where you keep control:

http://www.gammon.com.au/serial

replaysMike: Alexander,

A+! I hadn't actually looked at the source for readBytes(), and maybe that should have been my starting point. I wasn't aware that it was using timedRead() as well as a loop, figured it was going to be doing a block copy from it's internal buffer. It would definitely be more advantageous to do the standard Serial.read() and let my runtime loop handle the data as it comes in. This way I'm not blocking any mission critical timing.

Thanks for making it clear!

Sure thing :). It was a nice suggestion you made and indeed gave me the motivation to look up the thing myself... so your question advanced us both. By the way I think that looking more closely in the source does not seem impossible to me that there could be a direct access to the memory that would allow you to do some "block copy" kind of stuff.

Indeed , how it works? is maybe well explained here: http://binglongx.wordpress.com/2011/10/26/arduino-serial-port-communication/. As the reading of this suggests to me there the data comming via the UART is already somewhere in SRAM and it must hence be possible to reach it.

the Hardwareserial::read() should tell you the meachnics.... have a peek.... (not a peek() though ;)

[quote author=Nick Gammon link=topic=153174.msg1150064#msg1150064 date=1362889371] I don't like all those fancy "do everything for you, don't you worry about that" function calls. [/quote]

In clear you prefere Serial.read() of Serial.readBytes()? I do understand Nick, still in the pursuit of the least "do everything for you"-function can we stop at read()? How would you access the real HardwareSerial buffer? I'd be glad for you sharing you insight!

have a nice day (at least here in Berlin it is day... you are in mmon.com.au*, anyhow enjoy your time

alexander_senseo:
In clear you prefere Serial.read() of Serial.readBytes()?
I do understand Nick, still in the pursuit of the least “do everything for you”-function can we stop at read()?
How would you access the real HardwareSerial buffer?

I don’t mind Serial.read and Serial.available. They are “low level” enough for me. Accessing hardware registers makes code non-portable, although it has to be done at times.

But stuff like timedRead is fine, I suppose. But it “blocks”:

// private method to read stream with timeout
int Stream::timedRead()
{
  int c;
  _startMillis = millis();
  do {
    c = read();
    if (c >= 0) return c;
  } while(millis() - _startMillis < _timeout);
  return -1;     // -1 indicates timeout
}

Generally I advise people to have non-blocking code. While you are doing this timedRead you aren’t doing anything else.

have a nice day (at least here in Berlin it is day… you are in mmon.com*.au**, anyhow enjoy your time

It’s hot here in Melbourne. About 10 days in a row over 30C, and not much cooler at night.