-1

There is a function written in C that calculates CRC16 CCITT. It helps reading data from RFID reader - and basically works fine. I would like to write a function in Java that would do similar thing. I tried online converter page to do this, but the code I got is garbage. Could you please take a look at this and advice why Java code that should do the same generates different crc? Please find attached original C function:

void CRC16(unsigned char * Data, unsigned short * CRC, unsigned char Bytes)
{
    int i, byte;
    unsigned short C;

    *CRC = 0;
    for (byte = 1; byte <= Bytes; byte++, Data++)
    {
        C = ((*CRC >> 8) ^ *Data) << 8;
        for (i = 0; i < 8; i++)
        {
            if (C & 0x8000)
                C = (C << 1) ^ 0x1021;
            else
                C = C << 1;
        }
        *CRC = C ^ (*CRC << 8);
    }
}

And here is the different CRC function written in JAVA that should calculate the same checksum, but it does not:

public static int CRC16_CCITT_Test(byte[] buffer) {
     int wCRCin = 0x0000; 
     int wCPoly = 0x1021; 
     for (byte b : buffer) {
         for (int i = 0; i < 8; i++) {
             boolean bit = ((b >> (7 - i) & 1) == 1);
             boolean c15 = ((wCRCin >> 15 & 1) == 1);
             wCRCin <<= 1;
             if (c15 ^ bit)
                 wCRCin ^= wCPoly;
         }
     }
     wCRCin &= 0xffff;
     return wCRCin;
    }

When I try calculating 0,2,3 numbers in both functions I got different results: for C function it is (DEC): 22017 for JAVA function it is (DEC): 28888

OK. I have converter C into Java code and got it partially working.

public static int CRC16_Test(byte[] data,  byte bytes) {
            int dataIndex = 0;
            short c;
            short [] crc= {0};

            crc[0] = (short)0;
            for(int j = 1; j <= Byte.toUnsignedInt(bytes); j++, dataIndex++) {
                c = (short)((Short.toUnsignedInt(crc[0]) >> 8 ^ Byte.toUnsignedInt(data[dataIndex])) << 8);
                for(int i = 0; i < 8; i++) {
                    if((Short.toUnsignedInt(c) & 0x8000) != 0) {
                        c = (short)(Short.toUnsignedInt(c) << 1 ^ 0x1021);
                    } else {
                        c = (short)(Short.toUnsignedInt(c) << 1);
                    }
                }
                crc[0] = (short)(Short.toUnsignedInt(c) ^ Short.toUnsignedInt(crc[0]) << 8);
            }
        return crc[0];
        }

It gives the same CRC values as C code for 0,2,3 numbers, but i.e. for numbers 255, 216, 228 C code crc is 60999 while JAVA crc is -4537.

OK. Finally thanks to your pointers I got this working. The last change required was changing 'return crc[0]' to:

return (int) crc[0] & 0xffff;

... and it works... Many thanks to all :)

bzc0fq
  • 579
  • 1
  • 3
  • 18
  • 1
    Have you stepped through the code in your IDE debugger? What did you find? – Jim Garrison Jan 11 '21 at 21:40
  • I use Eclipse for Java and it compiles fine... no issues – bzc0fq Jan 11 '21 at 21:42
  • 1
    I'm not going to debug it for you. However, one thing sticks out -- I think you misunderstand the difference between signed and unsigned right shifts. – Jim Garrison Jan 11 '21 at 21:44
  • 1
    Also, "it compiles" means only that you got the syntax right... it says nothing about whether or not the code is correct. You need to step through it in Eclipse, one line at a time, and watch what is happening to the variables. You can then find where it deviates from your expectation. – Jim Garrison Jan 11 '21 at 21:46
  • if you refer to C function - it generates the CRC as device where it is connected... but OK, I will take a look at this. Thanks – bzc0fq Jan 11 '21 at 21:48
  • 2
    You do a right shift on an `unsigned short` value in C. Java does not have unsigned values (except `char` and it gets promoted in expressions). Consider what that means for right shifts. – Jim Garrison Jan 11 '21 at 21:53
  • related? https://stackoverflow.com/questions/24694713/calculation-of-ccitt-standard-crc-with-polynomial-x16-x12-x5-1-in-java – Jocke Jan 11 '21 at 22:11
  • OK. I have converted C code into Java. It works fine with number below 128... if I calculate crc16 for the values above 128 then I got a negative crc value... I update post with the JAVA code – bzc0fq Jan 11 '21 at 22:32

1 Answers1

2

There is nothing wrong. For a 16 bit value, –4537 is represented as the exact same 16 bits as 60999 is. If you would like for your routine to return the positive version, convert to int (which is 32 bits) and do an & 0xffff.

Mark Adler
  • 101,978
  • 13
  • 118
  • 158
  • 1
    OK. I have changed last line to return (int) crc[0] & 0xffff; and it works fine now. Thanks! – bzc0fq Jan 11 '21 at 23:09