Arduino sending data with checksum CRC16

Hello,

I have tried to send an array with data and at the end a checksum. I really does not see where the issue is. I have tried to see through my coding, but I can not see the issue. Can someone help to find where the problem is?
I will get the data from the array, if I delete the condition in the if-statement in the readCommand() function.

Instead of this:

else if(m == '\n' && crcData[0] == crcDataRec[0] && crcData[1] == crcDataRec[1])

I use this:

else if(m == '\n')

and get the correct data.

But now, I will creat the checksum from the received data again and compare it with the received one. If that is true, the received data will be used. Any idea?

Here is the sender code:

/*Arduino 1 has the SC16IS750 connected on SDA/SCL
 *TX/RX of the SC16IS750 is connected to Arduino 2
 *VCC/GND
 *I2C of the SC16IS750 is connected to VCC
 *A0 and A1 of the SC16IS750 is connected as shown in the address table below
 */
 
#include <Wire.h>
#include <SC16IS750.h>

SC16IS750 i2cuart = SC16IS750(SC16IS750_PROTOCOL_I2C,SC16IS750_ADDRESS_AA);   /*Address table:  A1    A0    Address
                                                                                               VDD   VDD    0x90 => AA
                                                                                               VDD   GND    0x92 => AB
                                                                                               VDD   SCL    0x94 => AC
                                                                                               VDD   SDA    0x96 => AD
                                                                                               GND   VDD    0x98 => BA
                                                                                               GND   GND    0x9A => BB
                                                                                               GND   SCL    0x9C => BC
                                                                                               GND   SDA    0x9E => BD
                                                                                               SCL   VDD    0xA0 => CA
                                                                                               SCL   GND    0xA2 => CB
                                                                                               SCL   SCL    0xA4 => CC
                                                                                               SCL   SDA    0xA6 => CD
                                                                                               SDA   VDD    0xA8 => DA
                                                                                               SDA   GND    0xAA => DB
                                                                                               SDA   SCL    0xAC => DC
                                                                                               SDA   SDA    0xAE => DD
                                                                                               */

const byte bufferSize {10};
char serialBuffer[bufferSize+1] {""};
char incomingData[bufferSize];
char value[bufferSize];
char variable[bufferSize];
uint16_t crc = 0;    //checksum crc
byte crcData[2];        //create array for the received checksum
byte crcDataRec[2];        //create array for the new calculated checksum from received data

int E = 0;
int F = 0;
int G = 0;
int H = 0;
int BUT = 0;


void setup()
{
  i2cuart.begin(38400);
  Serial.begin(38400);
}

void loop()
{
  readCommand();
  
  
  Serial.print("E = ");
  Serial.println(E);
  Serial.print("F = ");
  Serial.println(F);
  Serial.print("G = ");
  Serial.println(G);
  Serial.print("H = ");
  Serial.println(H);
  Serial.print("BUT = ");
  Serial.println(BUT);

  
  command("A0");
  command("B55");
  command("C180");
  command("D125");
  command("@12");
 
}



void command(String value) {
  memset(serialBuffer, 0, sizeof serialBuffer);
  sendToI2CUART(serialBuffer, value);
}


void sendToI2CUART (char *const buffer, String command)
{
  command.toCharArray(buffer, bufferSize);
  const size_t characters {strlen(buffer)};
  Serial.print("laenge: "); Serial.println(characters);

  for(byte index = 0; index < characters; index++){            //create the checksum for the array data[i] with 0 <= i <= 3
        crc16(buffer[index]);                                  //call the function crc16
      }
      crc = getCRC();
      byte crcIndex = characters;
      byte crcIndex2 = crcIndex++;
      buffer[crcIndex] = crc >> 8;                         //store checksum in data array
      buffer[crcIndex2] = crc;
      
  for (byte i = 0; i < characters; i++)
  {
    i2cuart.write(buffer[i]);
    Serial.print("gesendet: ");
    Serial.println(buffer[i]);
  }
  i2cuart.write('\0');
  i2cuart.write(buffer[crcIndex]);
  Serial.println(buffer[crcIndex]);
  i2cuart.write(buffer[crcIndex2]);
  Serial.println(buffer[crcIndex2]);
  i2cuart.write('\n');

}


//Calculates CRC16 of nBytes of data[index] in byte array
void crc16(uint8_t data) {

  int i;
  crc = crc ^ ((uint16_t)data << 8);
  for (i=0; i<8; i++){
    if (crc & 0x8000){
      crc = (crc << 1) ^ 0x1021;
    }
    else{
      crc <<= 1;
    }
  }
}

uint16_t getCRC() {
  return crc;
}


void readCommand(){

  char var;
  int val = 0;
  static byte i = 0;
  static byte j = 0;
  static byte k = 0;

  while(i2cuart.available()) {
    char m = i2cuart.read();
    if(m != '\0' && m != '\n') {
      incomingData[i++] = m;
    }

    else if(m == '\0') {
      crcData[0] = i2cuart.read();
      crcData[1] = i2cuart.read();

      for(byte index = 0; index <= strlen(incomingData); index++){            //create the checksum for the array data[i] with 0 <= i <= 3
        crc16(incomingData[index]);                                  //call the function crc16
      }
      crc = getCRC();
      crcDataRec[0] = crc >> 8;                         //store checksum in data array
      crcDataRec[1] = crc;

      Serial.print("crcData[0] = ");
      Serial.println(crcData[0]);
      Serial.print("crcDataRec[0] = ");
      Serial.println(crcDataRec[0]);
      Serial.print("crcData[1] = ");
      Serial.println(crcData[1]);
      Serial.print("crcDataRec[1] = ");
      Serial.println(crcDataRec[1]);
    }
    
    else if(m == '\n' && crcData[0] == crcDataRec[0] && crcData[1] == crcDataRec[1]) {
      i = 0;
      while(i <= strlen(incomingData) ) {
        if(isdigit(incomingData[i]) == true) {
          value[j] = incomingData[i];
          j++;
          i++;
        }
        else {
          variable[k] = incomingData[i];
          k++;
          i++;
        }
      }
      memset(incomingData, 0, sizeof incomingData);
      j = 0;
      k = 0;
      i = 0;
      
      val = atoi(value);  //making the integer part
      var = variable[0];

      memset(value, 0, sizeof value);
      memset(variable, 0, sizeof variable);

      switch(var) {
      case 'E' : E = val;
                 break;
      case 'F' : F = val;
                 break;
      case 'G' : G = val;
                 break;
      case 'H' : H = val;
                 break;
      case '#' : BUT = val;
                 break;
      }
    }
  }
}

Here is the receiver code:

/*Arduino 2 has the SC16IS750 connected on TX/RX
 */

const byte bufferSize {10};
char serialBuffer[bufferSize+1] {""};
char incomingData[bufferSize];
char value[bufferSize];
char variable[bufferSize];
uint16_t crc = 0;    //checksum crc
byte crcData[2];
byte crcDataRec[2];

int A = 0;
int B = 0;
int C = 0;
int D = 0;
int BUT = 0;

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

void loop() {

  readCommand();

  
  Serial.print("A = ");
  Serial.println(A);
  Serial.print("B = ");
  Serial.println(B);
  Serial.print("C = ");
  Serial.println(C);
  Serial.print("D = ");
  Serial.println(D);
  Serial.print("BUT = ");
  Serial.println(BUT);


  command("E10");
  command("F5");
  command("G147");
  command("H251");
  command("#33");
  
}


void command(String value) {
  memset(serialBuffer, 0, sizeof serialBuffer);
  sendToUART(serialBuffer, value);
}


void sendToUART (char *const buffer, String command)
{
  command.toCharArray(buffer, bufferSize);
  const size_t characters {strlen(buffer)};

  for(byte index = 0; index < characters; index++){            //create the checksum for the array data[i] with 0 <= i <= 3
        crc16(buffer[index]);                                  //call the function crc16
      }
      crc = getCRC();
      byte crcIndex = characters;
      byte crcIndex2 = crcIndex++;
      buffer[crcIndex] = crc >> 8;                         //store checksum in data array
      buffer[crcIndex2] = crc;

  for (byte i = 0; i < characters; i++)
  {
    Serial.write(buffer[i]);
  }
  Serial.write('\0');
  Serial.write(buffer[crcIndex]);
  Serial.write(buffer[crcIndex2]);
  Serial.write('\n');

}


//Calculates CRC16 of nBytes of data[index] in byte array
void crc16(uint8_t data) {

  int i;
  crc = crc ^ ((uint16_t)data << 8);
  for (i=0; i<8; i++){
    if (crc & 0x8000){
      crc = (crc << 1) ^ 0x1021;
    }
    else{
      crc <<= 1;
    }
  }
}

uint16_t getCRC() {
  return crc;
}


void readCommand(){

  char var;
  int val = 0;
  static byte i = 0;
  static byte j = 0;
  static byte k = 0;
  
  while(Serial.available()) {
    char m = Serial.read();
    if(m != '\0' && m != '\n') {
      incomingData[i++] = m;
    }

    else if(m == '\0') {
      crcData[0] = Serial.read();
      crcData[1] = Serial.read();

      for(byte index = 0; index < i++; index++){            //create the checksum for the array data[i] with 0 <= i <= 3
        crc16(incomingData[index]);                                  //call the function crc16
      }
      crc = getCRC();
      crcDataRec[0] = crc >> 8;                         //store checksum in data array
      crcDataRec[1] = crc;

      Serial.print("crcData[0] = ");
      Serial.println(crcData[0]);
      Serial.print("crcDataRec[0] = ");
      Serial.println(crcDataRec[0]);
      Serial.print("crcData[1] = ");
      Serial.println(crcData[1]);
      Serial.print("crcDataRec[1] = ");
      Serial.println(crcDataRec[1]);
    }
    
    else if(m == '\n' && crcData[0] == crcDataRec[0] && crcData[1] == crcDataRec[1]) {
      //Serial.print("incomingData: ");
      //Serial.println(incomingData);
      i = 0;
      while(i <= strlen(incomingData) ) {
        if(isdigit(incomingData[i]) == true) {
          value[j] = incomingData[i];
          j++;
          i++;
        }
        else {
          variable[k] = incomingData[i];
          k++;
          i++;
        }
      }
      memset(incomingData, 0, sizeof incomingData);
      j = 0;
      k = 0;
      i = 0;
      //Serial.print("value: ");
      //Serial.println(value);
      //Serial.print("variable: ");
      //Serial.println(variable);
      
      val = atoi(value);  //making the integer part
      var = variable[0];
      //Serial.println(var);
      //Serial.println(val);
      memset(value, 0, sizeof value);
      memset(variable, 0, sizeof variable);

      switch(var) {
      case 'A' : A = val;
                 break;
      case 'B' : B = val;
                 break;
      case 'C' : C = val;
                 break;
      case 'D' : D = val;
                 break;
      case '@' : BUT = val;
                 break;
      }
    }
  }
}

I don't know what that means.

Please describe what you expect the program to do, and what it does instead.

Sorry!
I send the data that is written in the command() function at the beginning of each code (sender and receiver). If I will remove in the readCommand()-function the comparison of the crc checksum (as described above), I will get the sent data vice versa received on the other Arduino.
If I try to compare the checksums, both Arduinos only send the data, but does not receive it. The issue is somewhere with the checksum CRC16 I have created. But I do not see where the problem is.

Have you printed out the checksums to see if they are the same?

There are many different CRC16 checksum calculations.

I have written some library routines, for a radio device, that append a 16bit CRC to the end of an array payload, so that the CRC of the payload goes out with the packet. The radio receiver can then check the payload is valid since the two bytes at the end of the packet should be the CRC.

The major troubleshooting step in getting this working was to print out the entire outgoing packet in HEX bytes and checking that the correct CRC was indeed at the packet end. The receiver would do the same, printout the HEX bytes of the received packet so you could see what was actually going on.

Fairly easy to then troubleshoot issues, if you have a list of HEX bytes being sent and HEX bytes received.

I have tried to add the prints on the serial monitor as in the code I have posted. The sent CRC is not the same, but I do not see where I have the issue. I calculate the checksum from the data I will send and send it at the end with the data. The receiver reads the data and stores the sent checksum to the crcData array I have created. Then I calculate the checksum from the received data again and compare it with the sent one. These two checksums are not the same.
If someone take a look at my code and see the problem, I am really thankful for all ideas!

To show the checksum on the serial monitor in HEX or as bytes, that is not a problem I think. That is only a visual thing what you love to see. But sure, I can print it out as a HEX number of course.

  while (Serial.available())
  {
    char m = Serial.read();
    if (m != '\0' && m != '\n')
    {
      incomingData[i++] = m;
    }
    else if (m == '\0')
    {
      crcData[0] = Serial.read();  //how do you know that there is data available to read ?
      crcData[1] = Serial.read();

In the receiver code you are reading data when there may not be any available

I send the '\0' character and after that the checksum. The end mark is '\n' to show the end of transmitted data. Am I making a mistake?

Whatever you are sending you are reading from Serial with no guarantee that there is anything to read

Here I send the data:

for (byte i = 0; i < characters; i++)
  {
    i2cuart.write(buffer[i]);
    Serial.print("sent: ");
    Serial.println(buffer[i]);
  }
  i2cuart.write('\0');
  i2cuart.write(buffer[crcIndex]);
  Serial.println(buffer[crcIndex]);  //to show the sent data on the serial monitor
  i2cuart.write(buffer[crcIndex2]);
  Serial.println(buffer[crcIndex2]);  //to show the sent data on the serial monitor
  i2cuart.write('\n');

and in the receiver code to receive it with the same structure:

while(Serial.available()) {
    char m = Serial.read();
    if(m != '\0' && m != '\n') {
      incomingData[i++] = m;
    }

    else if(m == '\0') {
      crcData[0] = Serial.read();
      crcData[1] = Serial.read();

Because I am sending over the SC16IS750, I send it over I2C and on the other end I read it from serial.
Is there really a mistake I have made? I think I should try it tomorrow again with a empty and fresh head...

while(Serial.available()) {
    char m = Serial.read();
    if(m != '\0' && m != '\n') {
      incomingData[i++] = m;
    }

    else if(m == '\0') {
      crcData[0] = Serial.read();  //how do you know that data is available ?
      crcData[1] = Serial.read(); //how do you know that data is available ?

Yes, now I see the problem! I do not know how to fix that. That means, the first if-statement that stores the data to incomingData could also read the crcData after the '\0'. It should read the data that comes after the '\0', but without it and stores to the crcData array. Any suggestions for that?

I have not looked in detail, but it looks like you need to implement a state machine so that only the appropriate section of code is executed when required

Fix it by calling Serial.available() and making sure that there are characters to read before calling Serial.read().

Serial data transfer is SLOW.

Perhaps I can separate the two sections. First when serial.available() and the received character is not '\0', it will store the data to incomingData array, and the second if-statement is looking for serial.available() and the received character is not '\n', then it will store the data to crcData.
I will test it out!

A state machine would help, as suggested above.

Something like that? I will try it out this evening!

byte state = 0;

while(Serial.available() > 0){

	m = Serial.read();

	if(m == '\0'){
	state = 1;
	}
	else if(m == '\n'){
	state = 2;
	}

	switch(state){
		case 0: fill the incomingData array
			break;
		case 1: fill the crcData array
			break;
		case 2: end mark detected, store the incomingData array as needed
			state = 0;
			break;
	}
}

I have adapted the switch/case option to my code. It looks a lot better as yesterday! Thanks a lot for giving the direction to the state machine.
Here I have the untested code for the master Arduino (sender):

/*Arduino 1 has the SC16IS750 connected on SDA/SCL
 *TX/RX of the SC16IS750 is connected to Arduino 2
 *VCC/GND
 *I2C of the SC16IS750 is connected to VCC
 *A0 and A1 of the SC16IS750 is connected as shown in the address table below
 */
 
#include <Wire.h>
#include <SC16IS750.h>

SC16IS750 i2cuart = SC16IS750(SC16IS750_PROTOCOL_I2C,SC16IS750_ADDRESS_AA);   /*Address table:  A1    A0    Address
                                                                                               VDD   VDD    0x90 => AA
                                                                                               VDD   GND    0x92 => AB
                                                                                               VDD   SCL    0x94 => AC
                                                                                               VDD   SDA    0x96 => AD
                                                                                               GND   VDD    0x98 => BA
                                                                                               GND   GND    0x9A => BB
                                                                                               GND   SCL    0x9C => BC
                                                                                               GND   SDA    0x9E => BD
                                                                                               SCL   VDD    0xA0 => CA
                                                                                               SCL   GND    0xA2 => CB
                                                                                               SCL   SCL    0xA4 => CC
                                                                                               SCL   SDA    0xA6 => CD
                                                                                               SDA   VDD    0xA8 => DA
                                                                                               SDA   GND    0xAA => DB
                                                                                               SDA   SCL    0xAC => DC
                                                                                               SDA   SDA    0xAE => DD
                                                                                               */

const byte bufferSize {10};
char serialBuffer[bufferSize+1] {""};
char incomingData[bufferSize];
char value[bufferSize];
char variable[bufferSize];
uint16_t crc = 0;    //checksum crc
byte crcData[2];
byte crcDataRec[2];

int E = 0;
int F = 0;
int G = 0;
int H = 0;
int BUT = 0;


void setup()
{
  i2cuart.begin(38400);
  Serial.begin(38400);
}

void loop()
{
  readCommand();
  
  
  Serial.print("E = ");
  Serial.println(E);
  Serial.print("F = ");
  Serial.println(F);
  Serial.print("G = ");
  Serial.println(G);
  Serial.print("H = ");
  Serial.println(H);
  Serial.print("BUT = ");
  Serial.println(BUT);

  
  command("A0");
  command("B55");
  command("C180");
  command("D125");
  command("@12");
 
}



void command(String value) {
  memset(serialBuffer, 0, sizeof serialBuffer);
  sendToI2CUART(serialBuffer, value);
}


void sendToI2CUART (char *const buffer, String command)
{
  command.toCharArray(buffer, bufferSize);
  const size_t characters {strlen(buffer)};
  Serial.print("length: "); Serial.println(characters);

  for(byte index = 0; index < characters; index++){            //create the checksum for the array data[i] with 0 <= i <= 3
        crc16(buffer[index]);                                  //call the function crc16
      }
      crc = getCRC();
      byte crcIndex = characters;
      byte crcIndex2 = crcIndex++;
      buffer[crcIndex] = crc >> 8;                         //store checksum in data array
      buffer[crcIndex2] = crc;
      
  for (byte i = 0; i < characters; i++)
  {
    i2cuart.write(buffer[i]);
    Serial.print("sent: ");
    Serial.println(buffer[i]);
  }
  i2cuart.write('\0');
  i2cuart.write(buffer[crcIndex]);
  Serial.println(buffer[crcIndex]);
  i2cuart.write(buffer[crcIndex2]);
  Serial.println(buffer[crcIndex2]);
  i2cuart.write('\n');

}


//Calculates CRC16 of nBytes of data[index] in byte array
void crc16(uint8_t data) {

  int i;
  crc = crc ^ ((uint16_t)data << 8);
  for (i=0; i<8; i++){
    if (crc & 0x8000){
      crc = (crc << 1) ^ 0x1021;
    }
    else{
      crc <<= 1;
    }
  }
}

uint16_t getCRC() {
  return crc;
}


void readCommand(){

  char var;
  int val = 0;
  static byte i = 0;
  static byte j = 0;
  static byte k = 0;
  byte state = 0;

  while(i2cuart.available()) {
    char m = i2cuart.read();
    if(m == '\0') {
      state = 1;
      i = 0;
    }

    if(m == '\n') {
      state = 2;
      i = 0;
    }

    switch(state){
      case 0: incomingData[i++] = m;
              break;
      case 1: crcData[i++] = m;
              break;
      case 2: for(byte index = 0; index <= strlen(incomingData); index++){            //create the checksum for the array data[i] with 0 <= i <= 3
                crc16(incomingData[index]);                                  //call the function crc16
              }
              crc = getCRC();
              crcDataRec[0] = crc >> 8;                         //store checksum in data array
              crcDataRec[1] = crc;

              Serial.print("crcData[0] = ");
              Serial.println(crcData[0]);
              Serial.print("crcDataRec[0] = ");
              Serial.println(crcDataRec[0]);
              Serial.print("crcData[1] = ");
              Serial.println(crcData[1]);
              Serial.print("crcDataRec[1] = ");
              Serial.println(crcDataRec[1]);

              if(crcData[0] == crcDataRec[0] && crcData[1] == crcDataRec[1]) {
                while(i <= strlen(incomingData) ) {
                  if(isdigit(incomingData[i]) == true) {
                    value[j] = incomingData[i];
                    j++;
                    i++;
                  }
                  else {
                    variable[k] = incomingData[i];
                    k++;
                    i++;
                  }
                }
                memset(incomingData, 0, sizeof incomingData);
                j = 0;
                k = 0;
                i = 0;
      
                val = atoi(value);  //making the integer part
                var = variable[0];

                memset(value, 0, sizeof value);
                memset(variable, 0, sizeof variable);

                switch(var) {
                  case 'E' : E = val;
                             break;
                  case 'F' : F = val;
                             break;
                  case 'G' : G = val;
                             break;
                  case 'H' : H = val;
                             break;
                  case '#' : BUT = val;
                             break;
                }
              }
              else if(crcData[0] != crcDataRec[0] || crcData[1] != crcDataRec[1]){
                memset(incomingData, 0, sizeof incomingData);
              }
              state = 0;
    }
  }
}

I hope to find some time tomorrow to test it! If someone would like to take a look at it and see something that could be wrong, I am happy to know and correct it!

When actions are completed, like getting the CRC value, then you need to reset the state variable.