0

I'm sending command and parameters from one arduino board to another one. I want to validate whether the data has been corrupted or not at the other end. I'm looking for a basic sanity validation.

My packet looks like

struct Command {
   uint8_t id,
   uint8_t action,
   int param
}

How would I go about creating CRC to validate at the other end? Thanks.

anz
  • 987
  • 7
  • 21
  • So the total message size is either 4 bytes (if int is 2 bytes) or 6 bytes (if int is 4 bytes)? If so, then an 8 bit CRC is probably good enough, assuming the bit error rate is low. – rcgldr Feb 09 '19 at 08:15

1 Answers1

1

Simple example:

unsigned crc8_koop(unsigned crc, unsigned char const *data, size_t len) {
    if (data == NULL)
        return 0;
    crc = ~crc & 0xff;
    while (len--) {
        crc ^= *data++;
        for (unsigned k = 0; k < 8; k++)
            crc = crc & 1 ? (crc >> 1) ^ 0xb2 : crc >> 1;
    }
    return crc ^ 0xff;
}

Call with data equal to NULL to get the initial CRC value.

Mark Adler
  • 101,978
  • 13
  • 118
  • 158
  • So from my example; If I have Command* comm, then should I be calling crc8_koop(initialCRC, &comm->id, 3) ? I have 3 types in my Command struct, and each would be 1 byte when converted to unsigned char. – anz Feb 11 '19 at 16:48
  • No, you need the number of bytes, not the number of things. Use `sizeof(struct command)` to get the number of bytes in your structure. (Probably 6.) So `crc8_koop(crc8_koop(0, NULL, 0), &comm->id, sizeof(struct Command))`. That is assuming that you transmit the structure as is. If you, for example, send the `int` as one or two bytes instead of four bytes, then you will need to process that separately to make sure you get the correct bytes to avoid endianess issues. – Mark Adler Feb 11 '19 at 16:52
  • I was assuming that since they're converted to unsigned char, it'd be 3 bytes for the 3 items. When I do sizeof(comm->...), I get 1 for the two uint8_t , and 2 for an int. So, that's 4. So, essentially I could add another variable in the struct that holds the CRC, and then when I'd pass 4 as len, then it would calculate CRC for the first 3 elements? Is it how it works?. Pardon my naivety. – anz Feb 11 '19 at 17:04
  • You are sending a message somehow, either sending bytes individually or assembling the bytes into a buffer that is sent. You simply run the exact bytes that you send through the CRC. Then send the resulting CRC byte. Repeat on the other end to check the message. – Mark Adler Feb 11 '19 at 18:37
  • I worked out the internal calculations. So if I understand correctly, the internal implementation is a randomized function, right? – anz Feb 14 '19 at 02:07
  • There's nothing random about it. The calculation is entirely deterministic. – Mark Adler Feb 14 '19 at 02:12
  • Sorry for my choice of word, I understand it's totally deterministic. I wanted to confirm if the operation you choose for the implementation were random (did the choice of operation ensured there are no bad case scenario?). It already looks more than good enough for my use-case. Just double checking. – anz Feb 14 '19 at 02:25
  • What operation did I choose? – Mark Adler Feb 14 '19 at 02:39
  • I might be creating more confusion here. I meant the complement, shifts and the XORs. – anz Feb 14 '19 at 03:12
  • Ah, you mean the definition of the CRC. I chose the CRC of an empty message to be zero just because that makes sense. I chose the initial register value to be non-zero, so that a message of all zeros doesn't always end up as zero, regardless of its length. (All one's is a common choice.) I chose a reflected CRC, since the shift down implementation is a little more efficient. I chose the polynomial based on [Koopman's research into CRC polynomials](https://users.ece.cmu.edu/~koopman/crc/). – Mark Adler Feb 14 '19 at 03:22
  • Perfect. I'll take a look at that. Thanks for the links and your patience on this. Appreciate it. – anz Feb 14 '19 at 03:28