missing serial data, possible buffer-overrun?

Hi all,

I’m trying to program an arduino to send a slimmed-down version of incoming data on the serial port, to a softwareSerial port.

This is what I’m trying to do:

I have a lot of mobiles each sending their position to my reception unit. The reception unit will output one phrase for each mobile that it receives. It does this on a serial port at a baudrate of 115200. The syntax looks slightly like NMEA, but for some reason they have decided not to fully follow the NMEA syntax. For example, there is no checksum.

An example:
$DSM00,063943,+48.06851,+007.28909,3885.0,63.0,208.1,0F (followed by a new line 0x0D 0x0A)

The 00 is the ID. Likewise there could be a 01, 02, AA, FF,…

There is a maximum of 28 ID’s at the same time. In case they are all online, there will be a gap of approximately 35 milliseconds between eacht start of a new phrase.

Since I’m using for my project only the position of ID 00 and 01, I figured it would be a good idea to have an arduino setup as a filter, to ignore all the other ID’s, and then pass this new stream to the next processor, so that that one has more processing time left to handle the actual data. I’m using an Atmega328 processor.

For the moment it seems like the $DSM00 data passes correctly, however the $DSM01 doesn’t pass a soon as the stream gets busy.

Since I’m an amateur programmer, I think I might have written a very poorly programmed sketch for the job which isn’t very efficient. My guess would be that because of the way it’s written, it loses too much time doing something and missed the next phrase which might be the one I’m actually after.

It’s just a guess though, I might be completely wrong.
Could someone offer some insight on the problem and advice a better way to do so? Or would the Atmega328 just not be up to the job to handle that amount of data?

thanks a lot!
Cheers,
Jens

int numberofbytes = 0;
int timeout = 250;
unsigned long marker;
int DSM00_received = 0;
int DSM01_received = 0;
char answer[100];
int number = 0;
char DSM00[7] = "$DSM00";
char DSM01[7] = "$DSM01";
char waste;

#include <SoftwareSerial.h>
SoftwareSerial out(9,10);

void setup() {
Serial.begin(115200); //incoming data
out.begin(115200); //stripped-down output

startsetup:
if(Serial.available()>0){
afterFirstBytes:
marker = millis();
afterFirstBytes2:
if(Serial.available()>0){
waste = Serial.read(); //discard any garbage data that might have been received already
goto afterFirstBytes;
} else {
if(millis()-marker > timeout){
reset(); } else { goto afterFirstBytes2;}
}
} else {
goto startsetup;
}
}
void loop() {
if(Serial.available() >0){
number = number + 1;
answer[number] = Serial.read();
}
else {
if(number>0){
if(answer[number]==10){
DSM00_received = 0;
DSM01_received = 0;
for (int i=1;i<7;i++){ // Verifies if the received phrase starts with "DSM00", one character at a time
if (answer[i]==DSM00[i-1]){
DSM00_received++;
}
}
if(DSM00_received==6){ //if the phrase starts with "DSM00", output that phrase
for(int i=1;i<number+1;i++){
out.write(answer[i]);
}
}
else { 
for(int i=0;i<7;i++){//Verifies if the received phrase starts with "DSM01", one character at a time
if(answer[i]==DSM01[i-1]){
DSM01_received++;
}
}
if(DSM01_received==6){ //if the phrase starts with "DSM01", output that phrase
for(int i=1;i<number+1;i++){
out.write(answer[i]);
}}}
number = 0;
}
}
}
}
void reset(){
numberofbytes = 0;
marker = millis();
}
SoftwareSerial out(9,10);
out.begin(115200); //stripped-down output

The fastest baud rate that I have been able to use, reliably, with software serial is 38400.

If you need 115200 baud, i would suggest a Mega or other Arduino compatible board with multiple hardware serial ports.

Would that also be an issue if SoftwareSerial is only used as an output (as is the case?)

Would that also be an issue if SoftwareSerial is only used as an output (as is the case?)

I did not know the answer to that question so I hooked up an Uno, running a short software serial sketch, to a Mega hardware serial port. I sent a string of 85 characters from the Uno to the Mega every 200 milliseconds at 115200 baud. To my surprise, the Mega hardware serial receives with no errors. Now, this is just a send (Uno) and receive (Mega) in isolation (no other code to interfere) over 6 inch (150mm) jumper wires so YMMV.

Then I had the Mega hardware serial send an 8 character message at 115200 to the Uno (software serial, 115200 baud). Many errors (not surprised).

So if you are sending from soft serial to hardware serial, maybe OK. Not so the other way round or soft serial to soft serial.

so I hooked up an Uno, running a short software serial sketch

Awesome! Thank you so much for the effort!

So if you are sending from soft serial to hardware serial, maybe OK. Not so the other way round or soft serial to soft serial.

Ok, so this is what I was indeed going for. I hardly ever use the software serial as a receive line just because of this reason. I don't suppose you still have the hardware setup to try and push it more to the limit (software --> hardware) with a pause of only 35ms?

I'm stuck in my hotel room in Sweden at the moment trying to figure this thing out with the limited resources I have at hand :slight_smile:

Thanks for the help so far! Greatly appreciated!

For receiving the data you may find the examples in Serial Input Basics useful.

…R

I can try it later today, I am curious now. A couple of hours.

For receiving the data you may find the examples in Serial Input Basics useful.

Wow thanks! I did not come across that one. I have modified your extended example (start and end marker) a bit and will be able to try this out in real life tomorrow!

// Example 3 - Receive with start- and end-markers

const byte numChars = 80;
char receivedChars[numChars];

boolean newData = false;

void setup() {
    Serial.begin(115200);
    //Serial.println("<Arduino is ready>");
}

void loop() {
    recvWithStartEndMarkers();
    showNewData();
}

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '

;
    char endMarker = 0x0a;//>’;
    char rc;

while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = ‘\0’; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

void showNewData() {
  boolean PlaneOrCar = false;
    if (newData == true) {
        //Serial.print("This just in … ");

if(receivedChars[3] == ‘0’){
          switch(receivedChars[4]){
            case ‘0’: PlaneOrCar = true; break; //plane
            case ‘1’: PlaneOrCar = true; break;  //car
            default: break;
          }
      }

if(PlaneOrCar==true){
        Serial.print(’


);
        Serial.println(receivedChars);
        }
        newData = false;
    }
}