Efficient Serial data processing

Hi,
let’s say i have code as shown below. My question is…what happens if there is more incoming data on the serial port while i am processing the previous data. In other words, if my code is executing in the “processCommand” method, and while this is happening data is also being written to the serial port, would i miss that data?

I ask because i have two boards and i am connecting these via the RX/TX pins so that i can send data to and from. what’s happening is that Board A writes two strings very quickly to the serial port, but Board B (for which the code below is shown) only seems to receive one of the strings. Any idea why this might happen?

#include <stdlib.h>
#include <Servo.h>
Servo motor1;
String readString;

void setup() {
motor1.attach(11);
}

void loop() {

while (!Serial.available());

while (Serial.available())
{
//expect data in format like F:50 or B:25
char c = Serial.read(); //gets one byte from serial buffer
readString += c;
delay(1); //delay to allow buffer to fill
}

if (readString.length() > 0)
{
processCommand(readString);
readString = “”;
}
}

Input received while your sketch was busy would be buffered (up to 64 bytes worth) - but that code to handle serial port input is horrible and does not represent a good way to do it.

Don’t use the problematic String class to buffer the received data.

Don’t use timed delays to slow the serial port handling code down to the speed you assume data will arrive at.

Don’t use a delay between successive bytes to indicate the start or end of a message.

Here is an example of a more conventional technique to buffer and handle serial port input. In this example, messages are terminated by a newline. There are many other ways to terminate messages, so use whatever method suits your message format.

void handleSerial()
{
    const int BUFF_SIZE = 32; // make it big enough to hold your longest command
    static char buffer[BUFF_SIZE+1]; // +1 allows space for the null terminator
    static int length = 0; // number of characters currently in the buffer

    if(Serial.available())
    {
        char c = Serial.read();
        if((c == '\r') || (c == '\n'))
        {
            // end-of-line received
            if(length > 0)
            {
                handleReceivedMessage(buffer);
            }
            length = 0;
        }
        else
        {
            if(length < BUFF_SIZE)
            {
                buffer[length++] = c; // append the received character to the array
                buffer[length] = 0; // append the null terminator
            }
            else
            {
                // buffer full - discard the received character
            }
        }
    }
}

void handleReceivedMessage(char *msg)
{
	if(strcmp(msg, "on") == 0)
	{
		// handle the command "on"
	}
	else
	{
		// etc
	}
}

By the way, please use code tags to post code, not quote tags.

Besides PeterH's suggestions, I suggest you to use a lower baud rate if you start losing data. The sender will have to slow down anyway, if it is faster than the receiver can process. Also if your data traffic is irregular (bursts of long strings), then you will have to increase the default Serial receive buffer if you don't want to drop baud rate to an unreasonably low value.

Below is some simple servo test code that uses a comma , as a delimiter so a delay is not needed. In the world of servos, the data transmission does not have to be super fast.

//zoomkat 3-5-12 simple delimited ',' string parse 
//from serial port input (via serial monitor)
//and print result out serial port

String readString;
#include <Servo.h> 
Servo myservo;  // create servo object to control a servo 

void setup() {
  Serial.begin(9600);

  myservo.writeMicroseconds(1500); //set initial servo position if desired
  myservo.attach(7);  //the pin for the servo control 
  Serial.println("servo-delomit-test-22-dual-input"); // so I can keep track of what is loaded
}

void loop() {

  //expect a string like 700, or 1500, or 2000,
  //or like 30, or 90, or 180,

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      if (readString.length() >0) {
        Serial.println(readString); //prints string to serial port out

        int n = readString.toInt();  //convert readString into a number

        // auto select appropriate value, copied from someone elses code.
        if(n >= 500)
        {
          Serial.print("writing Microseconds: ");
          Serial.println(n);
          myservo.writeMicroseconds(n);
        }
        else
        {   
          Serial.print("writing Angle: ");
          Serial.println(n);
          myservo.write(n);
        }

        //do stuff with the captured readString 
        readString=""; //clears variable for new input
      }
    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}

You don't need delays.

http://gammon.com.au/serial

Thanks for the suggestions. As it turned out...it seems when multiple commands are written to the serial port by Board A very quickly, on the receiving end of Board B...the data for both of those writes are read into the same buffer. So the problem wasn't that i was missing the data, i just was never processing the the second command because the code was assuming that each command would be read into the buffer one at a time. once i modified the code to check for '\n' and break out of the while loop, all worked well.

that said, i will take the suggestions you have made into consideration as i agree, dealing with strings does not seem very efficient.