0

I'm having an issue in my Arduino code after receiving a message from Serial.

The issue is that, upon receiving the message "START" via serial, the Arduino proceeds to execute the function startSequence() that, using two random numbers, fetches 8 values from a 2D matrix and stores these values in a char array.

The problem here is that even though this char array has been declared with a size of 8, the message "START" gets appended to the end of this char array and it shouldn't do this at all, this message should be completely discarded after handleReceivedMessage(char *msg). My code:

#include <Keypad.h>

const byte ROWS = 4;
const byte COLS = 4;

char hexaKeys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
char newSecretCode[8];
char introducedSecretCode[8];

byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};

int secretCodeIndex = 0;

Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

void setup() {
  Serial.begin(9600);
  delay(2000);  //Delay to allow initializations on Raspberry side
  Serial.println("COM:SETUP;INT_NAME:Keypad Puzzle;BAUD:9600");
  randomSeed(analogRead(0));
}

void loop() {
  if (Serial.available()) {
    processSerialMessage();
  }
  char customKey = customKeypad.getKey();
  if (customKey) {
    if (secretCodeIndex < 8) {
      introducedSecretCode[secretCodeIndex] = customKey;
      secretCodeIndex += 1;
    } else {
      secretCodeIndex = 0;
    }
  }
}

void processSerialMessage() {
  const int BUFF_SIZE = 32; // make it big enough to hold your longest command
  static char buffer[BUFF_SIZE + 1]; // +1 allows space for the null terminator
  static int length = 0; // number of characters currently in the buffer

  char c = Serial.read();
  if ((c == '\r') || (c == '\n')) {
    // end-of-line received
    if (length > 0) {
      handleReceivedMessage(buffer);
    }
    length = 0;
  }
  else {
    if (length < BUFF_SIZE) {
      buffer[length++] = c; // append the received character to the array
      buffer[length] = 0; // append the null terminator
    } else {
      // buffer full - discard the received character
    }
  }
}

void handleReceivedMessage(char *msg) {
  if (strcmp(msg, "START") == 0) {
    startSequence();
    Serial.println("COM:START_ACK;MSG:Set new code to " + String(newSecretCode));
  }else {
    // etc
  }
}

void startSequence() {
  for (int i = 0; i < 8; i++) {
    newSecretCode[i] = hexaKeys[random(0,ROWS)][random(0,COLS)];
  }
}

I've seen the code over and over and I can't seem to figure out why does the message I receive through serial manages to get appended to the end of an array whose size is only 8. Below are some examples of the output which is correct except for the "START" message that is at the end of the String.

Output generated by sending "START" command through serial

Thank you to everyone in advance for the help and if the mistake is obvious my apologies, but I've been through this code over and over and can't seem to find it.

5
  • It would help if you explained how you were expecting this to work. How were you expecting + String(newSecretCode) to know to add 8 characters? Commented Apr 24, 2020 at 17:46
  • The problem isn't there @DavidSchwartz the problem is that the message that I input via Serial should not be appended to the end of my array newSecretCode because I don't have that instruction anywhere in my code and yet, when I print the array, the message that I introduced in Serial magically appears at the end. That's what I'm failing to understand right now Commented Apr 24, 2020 at 18:02
  • So you didn't expect that part of the code to work? I'm puzzled. You ask why there are more than 8 characters added to the string. I'm asking why you were expecting 8 to be added. Commented Apr 24, 2020 at 18:05
  • @DavidSchwartz There must a miscommunication here. In the startSequence() function I specifically add 8 characters to the newSecretCode array and they were added to the array. But when I do print the outputs of the array, the contents of it plus the string that I entered via serial also appear. Commented Apr 24, 2020 at 18:13
  • The startSequence code doesn't add characters to an array. It sets characters to a particular value. So how were you expecting +String(newSecretCode) to know that you had set 8 characters? I don't understand why you expected exactly 8 characters to be added to the string. Did you think the code that did the adding would know how many characters you had set elsewhere in the code? How would it possibly know? Commented Apr 24, 2020 at 18:16

1 Answer 1

1

You need to null terminate newSecretCode if you expect it to act as a string. But it is better to not use the String class to convert something you don't need to convert. Print it this way:

void handleReceivedMessage(char *msg) {
  if (strcmp(msg, "START") == 0) {
    startSequence();
    Serial.println("COM:START_ACK;MSG:Set new code to " );
    for (int i=0; i<8; i++){
      Serial.print(newSecretCode[i]);
    }
  }else {
    // etc
  }
}

Serial data goes out byte by byte. The receiver on the other end just sees a continuous stream of bytes. It has no knowledge of whether you did that with one single print statement and a bunch of resources wasted on a String or if you did it with a separate print statement for each character.

Sign up to request clarification or add additional context in comments.

10 Comments

Or make newSecretCode one slot larger and null terminate it. But still don't waste anything on String to combine them. Just print with two separate lines of code. The receiver will never know the difference.
I understand and it is now working, marked as answer. But I still fail to understand the reason for why the message that I introduce via Serial input gets appended to the end of that char array, it's like somewhere is written something like newSecretCode + msg
@Pmsmm Can you explain how you were expecting the code to know to add 8 characters? If if you weren't expecting the code to know to add 8, you shouldn't be surprised some number other than 8 is added.
The reason is that apparently buffer resides in memory directly after newSecretCode array. When you call print on a char array it will start at the beginning and print till it hits a null character. It knows nothing of the length of your string. Since newSecretCode wasn't null terminated it just ran on past the end and into the buffer array and printed until it finally hit the null character at the end of that string.
Where it really gets confusing is when it does hit garbage but the first byte of garbage just happens to be a 0. Then it works. Then nothing bad happens. Until one day you add some line of code in some completely different part somewhere totally unrelated and suddenly garbage starts printing out because something got stored there. Then you're off looking at the new line you added and wondering how it had this mysterious effect.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.