Question

I have to create a CRC16 checksum for a firmware update. When I send this Data (converted from hex-string to byte[])

020000810000120000000002F001128100000C9462050C9481050C9481050C9481050C9481050C9481050C9481050C9481050C9481050C9481050C9481050C94

I get following CRC16 from the controller

-17514

now I try to check this in Java, but I can't get the same value.

This are the original functions in C:

static uint16_t crc16_update(uint16_t crc, uint8_t a)
{
  crc ^= a;
  for (unsigned i = 0; i < 8; ++i) {
    if (crc & 1)
      crc = (crc >> 1) ^ 0xA001;
    else
      crc = (crc >> 1);
  }
  return crc;
}


static uint16_t crc16(const uint8_t *b, size_t l)
{
  uint16_t crc = 0;
  while (l-- > 0)
    crc = crc16_update(crc, *b++);
  return crc;
}

this are my converted functions in java:

public static int crc16_update(int crc, int a) {
    crc ^= a;
    for (int i = 0; i < 8; ++i) {
        if ((crc & 1) != 0) {
            crc = (crc >> 1) ^ 0xA001;
        } else {
            crc = (crc << 1);
        }
    }
    return crc;
}

public static int crc16(byte[] bytes) {
    int crc = 0;
    for (byte b:bytes) {
        crc = crc16_update(crc, b);
    }
    return crc;
}

... but it doesn't work. What's wrong with it?

Was it helpful?

Solution 4

I've found the right way. Now it work's! I think the problem was the intern converting between short and int.

public static int crc16_update(int crc, byte a) {
    crc ^= ((a+128) & 0xff);
    for (int i = 0; i < 8; ++i) {
        if ((crc & 1) != 0) {
            crc = ((crc >>> 1) ^ 0xA001) & 0xffff;
        }
        else {
            crc = (crc >>> 1) & 0xffff;
        }
    }
    return crc;
}

public static short crc16(byte[] bytes) {
    int crc = 0;
    for (byte b : bytes) {
        crc = crc16_update(crc, b);
    }
    return (short) crc;
}

OTHER TIPS

public static int crc16_update(int crc, int a) {
    crc ^= a;
    for (int i = 0; i < 8; ++i) {
        if ((crc & 1) != 0) {
            crc = (crc >> 1) ^ 0xA001;
        } else {
            crc = (crc << 1);

As mentioned by looper, you have a >> 1 there in the C code.

        }
    }
    return crc;
}

Now for the other function:

public static int crc16(byte[] bytes) {
    int crc = 0;
    for (byte b:bytes) {
        crc = crc16_update(crc, b);

crc16_update takes an int as second argument in Java, a uint8_t in C. When the byte b has its most significant/sign bit set, the value is negative, and thus when converted to int as argument to crc16_update, sign-extended, thus you get a lot of 1-bits that you don't have in C.

You need to mask out all bits but the least significant 8,

crc16_update(crc, ((int)b) & 0xFF);

You problem is not that integers a signed in java but you use the wrong datatype. int has 32 bit and the algorithm you use is sensitive to the datasize of the types. Use short for 16 bit and byte for 8 bit.

Also use >>>, where necessary, as mentioned by @Anony-Mousse.

Try using the >>> operator.

In Java, this is the unsigned shift operator, as opposed to >> which preserves the sign.

Also note that uint16_t is a 16 bit type, as is short in Java. Try to use the appropriate bit length, when rewriting algorithms that work on a bit level.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top