1

I'm working on UART communication between an ESP32 (sender) and ESP8266 NodeMCU board(receiver).

The host is sending out the following character string:

Serial.println("2753192144$1&");

The 2753192144 is the payload. The $1& is the trailer of the packet - $1 signifies a particular option for the receiver and & is the termination character to signify that the packet is complete.

On the receiver end - this is what I have:

#define MAX_REC_STR_SIZE 10
#define REC_TRAILER_SIZE 4 // $1& and string terminator
#define TRUE_TRAILER_SIZE 2 // option size really

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

void loop() {
    if(Serial.available()){
    char data [MAX_REC_STR_SIZE + TRUE_TRAILER_SIZE + 1];
    Serial.readBytesUntil('&', data, MAX_REC_STR_SIZE + REC_TRAILER_SIZE); // data does not contain termination &
    data[MAX_REC_STR_SIZE + TRUE_TRAILER_SIZE + 1] = 0; // adding null terminator

    // Tokenizing
    char *payload = strtok(data, "$"); // getting payload
    char opt = strtok(NULL, "$")[0]; // getting option - 1 in our sample

    // Print
    Serial.println(payload);
    Serial.println(opt);
  }
}

This code results in a stack exception error in the serial monitor. If I remove the last line which prints opt, the payload print works fine and I get 2753192144in the serial output.

I tested this exact code out in a standard C compiler, except instead of the serial read part - I defined a character array with 2753192144$1& and used printf instead of Serial.println. See the code below

#include <stdio.h>
#include <string.h>

int main()
{
    char data[] = "2753192144$1";

    char *payload = strtok(data, "$");
    char opt = strtok(NULL, "$")[0];
    printf("Payload is %s and opt is %c", payload, opt);

    return 0;
}

This code outputs

Payload is 2753192144 and opt is 1 

This works fine. Any ideas why the Arduino sketch isn't working?

  • There are a number of "handy" functions, for example the readBytesUntil. They have a timeout. You can use those once, when you are a beginner. But after that you have to move on and place the characters in a buffer as soon as a character is available. One character at a time for every iteration of the arduino loop. Check if the buffer has enough data en then process the data in the buffer. When you expect 16 bytes, make a buffer of 40 bytes and prevent that it overflows. Your code is dangerous in a number of ways. – Jot Aug 8 '18 at 19:02
  • println sends two additional characters that will mess with your fixed message size. Also you have a buffer for 13 character, but put a limit on readBytesUntil to 14 characters. – gre_gor Aug 8 '18 at 19:12
  • @gre_gor Ah yes. That REC_TRAILER_SIZE in the readBytesUntil() should be TRUE_TRAILER_SIZE since the & itself isn't meant to be read. – FShiwani Aug 8 '18 at 19:32
  • @Jot Yeah. I noticed that a lot of people in other threads were manually reading data and was wondering why not many people were using this readBytesUntil() function. – FShiwani Aug 8 '18 at 19:35
2
data[MAX_REC_STR_SIZE + TRUE_TRAILER_SIZE + 1] = 0; // adding null terminator

That line places a 0 in the byte following the array.

If you define an array of size [x] you have slices [0] to [x-1] available. If you try accessing [x] you will be altering other items on the stack after the array.

That's called a buffer overrun and is one of the most common causes of programs crashing.

If you want to put a 0 at the end of the array, you should use

data[MAX_REC_STR_SIZE + TRUE_TRAILER_SIZE] = 0; // adding null terminator

You should also check that the strtok() calls actually return a valid pointer. If the incoming string is not in the right format and strtok() can't split the string up, it will return NULL. If you then try and access that NULL pointer as if it were a valid array you will have a nasty crash.

  • Ah yes. My mistake sorry. Let me make some amendments to the code to take into account all the comments. – FShiwani Aug 8 '18 at 19:28
  • I made that change. Didn't change anything. I added a check to see if a NULL was being returned by either other of the two strtok() commands. Code runs fine I use the char opt = strtok() line without doing any operations with it. But even checking if it's NULL crashes the program. – FShiwani Aug 8 '18 at 19:51
  • I printed out the strlen() of data and it's 12 so that must mean that includes the 10 digit payload and the $1. Not sure why the second strtok() is giving me so much trouble. Technically, the second strtok() should only be returning 1 character - the '1'. – FShiwani Aug 8 '18 at 19:55
  • UPDATE: char opt = strtok(NULL, "$")[0]; to char *opt = strtok(NULL, "$") seems to have fixed it some how. Not entirely sure why the first didn't work. Any ideas? – FShiwani Aug 8 '18 at 20:22
  • Could be something strange in the c library for the ESP8266. I don't know which it uses, but it certainly won't be the same as your PC... – Majenko Aug 8 '18 at 20:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.