0

I implemented a buffer on Arduino Mega 2560 using Code of Dan Royer as a base. The code runs perfectly fine on the Mega, but I wanted to use the enhanced features and power of the Arduino Due (which uses an ARM instead of the standard Atmel microprocessor).

On the Due I always get into an infinite loop while processing the buffer content due to it not exiting when the end of the buffer is reached. Does anyone know why this might happen? And do you have ideas on how to prevent this?

The commands given would be GCodes such as : "G01 X20.5 Y30;"

This is how the buffer is filled:

char buffer[MAX_BUF];  // where we store the message until we get a ';'
int sofar;  // how much is in the buffer

while(Serial.available() > 0) {  // if something is available
  char c=Serial.read();  // get it
  if(sofar<MAX_BUF-1) buffer[sofar++]=c;  // store it
  if(c==';') {
    // entire message received
    // we got a message and it ends with a semicolon
    buffer[sofar]=0;  // end the buffer so string functions work right
    processCommand();  // do something with the command
  }

The processCommand() then calls a function that searches the buffer for specific characters and returns the float that is directly behind this character:

/**
 * Look for character /code/ in the buffer and read the float that immediately follows it.
 * @return the value found.  If nothing is found, /val/ is returned.
 * @input code the character to look for.
 * @input val the return value if /code/ is not found.
 **/
float parsenumber(char code,float val) {
  char *ptr=buffer;
  while(ptr && *ptr && ptr<buffer+sofar) {
    if(*ptr==code) { // if /code/ is found
      return atof(ptr+1); // return the float behind it
    }
    ptr=strchr(ptr,' ')+1; // else increment pointer to next char after a space
  }
  return val; // if the end of the buffer is reached, return the default value
} 

Now, this code works perfectly fine on the Arduino Mega, but on the Due the while loop is never exited for some reason.

This is how it works on the Mega:

GCode: G1;
Parsenumber: code:F val:288.46
####
ASCII Code at ptr: 71.00
String at ptr: G1;
String at buffer end: 
#####
ptr incremented
ASCII Code at ptr: 0.00
String at ptr: 
String at buffer end: 
#####
End of Parse: return 288.46

But this is how it is on the Due:

GCode: G1;
Parsenumber: code:F val:288.46
#####
ASCII Code at ptr: 71.00
String at ptr: G1;
String at buffer end: 
#####
ptr incremented
ASCII Code at ptr: 128.00
String at ptr: € q 
String at buffer end: 
#####
ptr incremented
ASCII Code at ptr: 113.00
String at ptr: q 
String at buffer end: 
#####
ptr incremented
ASCII Code at ptr: 8.00
String at ptr: 
String at buffer end: 
#####
ptr incremented
ASCII Code at ptr: 128.00
String at ptr: € q 
String at buffer end: 
#####
ptr incremented
ASCII Code at ptr: 113.00
String at ptr: q 
String at buffer end: 
#####

and so on...

Thus, it seems to me that the exit condition ptr<buffer+sofar is never met. Unfortunately I have not been able to print memory addresses with the Arduino. Does anyone know anything?

shilovk
  • 11,718
  • 17
  • 75
  • 74
Louis
  • 1
  • 1
  • 1
    Incrementing pointer with `ptr=strchr(ptr,' ')+1;` is undefined behaviour, because of `strchr` doesn't find the `char` it return `NULL`. – LPs Jul 16 '15 at 10:29
  • @LPs that's probably deserving of an answer; undefined behaviour would explain the difference in outcomes on platforms. Best course of action is probably to refactor the code to do this in a robust manner rather than relying on the formatting of the string to be correct. – Matt Taylor Jul 16 '15 at 10:41
  • I tried adding a simple line of `if(ptr – Louis Jul 16 '15 at 11:52
  • 1
    @Louis Probably in Atmel platform, at NULL (address 0) there is a 0x00 value that make code work well. – LPs Jul 16 '15 at 12:02

2 Answers2

0

I post my comment to allow to close the question:

Incrementing pointer with ptr=strchr(ptr,' ')+1; is undefined behaviour, because of strchr doesn't find the char it return NULL.

You should check strchr return, before to assign it to ptr.

Probably on Atmel platform, there is a 0x00 at address NULL+1 that make your code work well.

Another possibility (I'm very noob on Arduino) is that strchr implementation in Atmel library is not returning NULL if the char is not found. I saw strchr implementation where, in case of char not found, the returned value was last char of string.

LPs
  • 16,045
  • 8
  • 30
  • 61
0

Insure buffer is a valid string before the while loop. (Maybe arduino initializes values to 0 by default - IDK. C does not and an infinite loop may result and cause "while loop is never exited".)

char buffer[MAX_BUF];
// int sofar;
int sofar = 0;  // Initialize to 0. 

buffer[0] = 0;  // Add 

During the while loop, append a null character after each time a character is appended. This is especially important should a ; is not found or the buffer is long. Is is not posted what happens to buffer after the while loop.

if (sofar<MAX_BUF-1) {
  buffer[sofar++] = c;
  buffer[sofar] = 0; // Add
 }
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256