After reading the following 2 articles:
https://hackingmajenkoblog.wordpress.com/2016/02/01/reading-serial-on-the-arduino/
https://hackingmajenkoblog.wordpress.com/2016/02/04/the-evils-of-arduino-strings/
I have get rid of the complete String class from my main program and went back to using character arrays. This seems to work reliably until some extent but once I start stress testing it, quickly turns out that it is not reliable at all!
Here is the complete code, you can load it into the mega and it will produce the same results (I have removed all other unnecessary parts from the code):
#define DEBUG
char Command_PC[64], Command_Xbee[64], Command[64];
int count=0;
bool Complete_PC=false;
bool Complete_Xbee=false;
void setup()
{
Serial.begin(9600);
Serial1.begin(9600);
} // END void setup
void comm() {
/* COMM FROM PC */
if (Serial.available()){
#ifdef DEBUG
Serial.println("PC: New command, collecting...");
#endif
count = 0;
memset(Command_PC, 0, sizeof(Command_PC));
while (Serial.available()){
char character = Serial.read();
if (character=='\n')
{
Complete_PC =true;
break;
}
Command_PC[count] = character;
count++;
}
}
/* COMM FROM Xbee */
if (Serial1.available()){
#ifdef DEBUG
Serial.println("Xbee: New command, collecting...");
#endif
count = 0;
memset(Command_Xbee, 0, sizeof(Command_Xbee));
while (Serial1.available()){
char character = Serial1.read();
if (character=='\n')
{
Complete_Xbee =true;
break;
}
Command_Xbee[count] = character;
count++;
}
}
delay(500);
if (Complete_Xbee || Complete_PC) {
if(Complete_Xbee)
strcpy(Command, Command_Xbee);
else
strcpy(Command, Command_PC);
#ifdef DEBUG
Serial.print("Command received: >");
Serial.print(Command);
Serial.println("<");
#endif
Complete_Xbee=false;
Complete_PC=false;
}
}
void loop()
{
comm();
} // END void loop
The code is simple, all it is intended to do that whether there is a command coming from the PC (USB) or Xbee (attached to hardware uart) process it and do further things. As long as you typing in commands manually it goes reliably for a while but even then after 10-15 commands it might screws up. The automated testing with:
for ((;;)); do echo HELLOWORLD > /dev/ttyACM0; done
Command received: >HELLOWORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOWORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOWORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOWORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOWORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOWORD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOWORL<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOWORLDELLOWORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HLOWORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELOWORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOWORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOORLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOWLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOWOD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOWOLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOWLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOWOLD<
ERR_INVALIDCMD
PC: New command, collecting...
Command received: >HELLOWLD<
ERR_INVALIDCMD
PC: New command, collecting...
Brings out the bug right away. Is there any problem with this code? Any ideas how to make this 100% reliable even if it takes slowing the main program down?
I have noticed that by adding: delay(500);
it makes it more stable. If this is not there it will even fail on the first manually entered command like:
PC: New command, collecting...
PC: New command, collecting...
PC: New command, collecting...
Command received: >lloworld<
By adding a delay to my test script:
for ((;;)); do echo HELLOWORLD > /dev/ttyACM0 && sleep 1; done
It runs stable for a while but after 15 mins testing it start misbehaving again:
Command received: >HELLOWORLD<
PC: New command, collecting...
Command received: >HELLOWORLD<
PC: New command, collecting...
PC: New command, collecting...
Command received: ><
PC: New command, collecting...
PC: New command, collecting...
Command received: ><
PC: New command, collecting...
PC: New command, collecting...
Command received: ><
PC: New command, collecting...
PC: New command, collecting...
Command received: ><