Reputation: 393
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?
Upvotes: 3
Views: 2216
Reputation: 393
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;
}
Upvotes: 0
Reputation: 183888
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);
Upvotes: 1
Reputation: 77464
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.
Upvotes: 0
Reputation: 9954
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.
Upvotes: 0