Бесконечный цикл из-за указателей на Arduino Due

Я реализовал буфер на Arduino Mega 2560, взяв за основу Code of Dan Royer. Код отлично работает на Mega, но я хотел использовать расширенные функции и мощность Arduino Due (в котором вместо стандартного микропроцессора Atmel используется ARM).

В Due я всегда попадаю в бесконечный цикл при обработке содержимого буфера из-за того, что он не выходит, когда достигается конец буфера. Кто-нибудь знает, почему это может произойти? И есть ли у вас идеи, как этого избежать?

Данными командами будут G-коды, такие как: «G01 X20.5 Y30;»

Вот так заполняется буфер:

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
  }

Затем processCommand() вызывает функцию, которая ищет в буфере определенные символы и возвращает число с плавающей запятой, которое находится непосредственно за этим символом:

/**
 * 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
} 

Теперь этот код отлично работает на Arduino Mega, но на Due цикл while по какой-то причине никогда не завершается.

Вот как это работает на Меге:

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

А вот как на Дуэ:

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: 
#####

и так далее...

Таким образом, мне кажется, что условие выхода ptr<buffer+sofar никогда не выполняется. К сожалению, мне не удалось распечатать адреса памяти с помощью Arduino. Кто-нибудь что-нибудь знает?


person Louis    schedule 16.07.2015    source источник
comment
Увеличение указателя с помощью ptr=strchr(ptr,' ')+1; является поведением undefined, поскольку strchr не находит char, он возвращает NULL.   -  person LPs    schedule 16.07.2015
comment
@LP, которые, вероятно, заслуживают ответа; поведение undefined объяснило бы разницу в результатах на разных платформах. Лучший способ действий, вероятно, состоит в том, чтобы реорганизовать код, чтобы сделать это надежным образом, а не полагаться на правильность форматирования строки.   -  person Matt Taylor    schedule 16.07.2015
comment
Я попытался добавить простую строку if(ptr<buffer) break; после ptr=strchr(ptr,' ')+1;, и это действительно сработало. Похоже, как писали LP, что ptr действительно генерировало неопределенное поведение. Разорвав цикл, когда ptr больше не было в пределах buffer, проблема может быть решена.   -  person Louis    schedule 16.07.2015
comment
@Louis Вероятно, на платформе Atmel в NULL (адрес 0) есть значение 0x00, благодаря которому код работает хорошо.   -  person LPs    schedule 16.07.2015


Ответы (2)


Я публикую свой комментарий, чтобы позволить закрыть вопрос:

Увеличение указателя с помощью ptr=strchr(ptr,' ')+1; является поведением undefined, поскольку strchr не находит символ, который возвращает NULL.

Вы должны проверить strchr return, прежде чем назначать его на ptr.

Вероятно, на платформе Atmel есть 0x00 по адресу NULL+1, благодаря которому ваш код работает хорошо.

Другая возможность (я очень плохо разбираюсь в Arduino) заключается в том, что реализация strchr в библиотеке Atmel не возвращает NULL, если символ не найден. Я видел реализацию strchr, где в случае ненахождения символа возвращаемое значение было последним символом строки.

person LPs    schedule 16.07.2015

Убедитесь, что buffer является допустимой строкой перед циклом while. (Возможно, arduino инициализирует значения 0 по умолчанию - IDK. C этого не делает, и может возникнуть бесконечный цикл, который приведет к тому, что цикл «пока цикл никогда не завершается».)

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

buffer[0] = 0;  // Add 

Во время цикла while добавляйте нулевой символ после каждого добавления символа. Это особенно важно, если ; не найден или буфер слишком длинный. Не сообщается, что происходит с buffer после цикла while.

if (sofar<MAX_BUF-1) {
  buffer[sofar++] = c;
  buffer[sofar] = 0; // Add
 }
person chux - Reinstate Monica    schedule 16.07.2015