0

I am currently writing a JAVA program which has to send data to a MyLaps decoder via socket (P3 protocol). The binary data has to include a 2-byte CRC code. In the MyLaps documentation there is the code in C to calculate the CRC. It also says that WORD is defined as an unsigned 16bits type.

C-Code

    WORD CRC16Table[256] ;
    
    // initialize the CRC16 table
    extern void InitCRC16( void ) {
      WORD i, j ;
      WORD crc ;
      for ( i = 0 ; i < 256 ; i += 1 ) {
        for ( crc = i << 8, j = 0 ; j < 8 ; j += 1 )
          crc = ( crc << 1 ) ^ ( ( crc & 0x8000 ) ? 0x1021 : 0 ) ;
        CRC16Table[ i ] = crc ;
      }
    } 

    // calculate the crc of a char array pointed at by p
    extern WORD CalcCRC16( unsigned char * p, WORD size ) {
      WORD crc = 0xFFFF ;
      WORD i ;
      for ( i = 0 ; i < size ; i++, p++ ) // for all chars
        crc = CRC16Table[ ( ( crc >> 8 ) & 255 ) ] ^ ( crc << 8 ) ^ *p ;
      return crc ;
    }

I wanted to convert this C-Code to java code. As java does not know an unsigned 2-byte number I used data type char which is also a 2-byte

JAVA Code

    // initialize the CRC16 table
    public static char[] InitCRC16() {
      char i, j;
      char crc;
      char[] CRC16Table = new char[256];
    
      for (i = 0; i < 256; i++) {
        crc = (char) (i << 8);
        for (j = 0; j < 8; j++) {
          crc = (char) ((crc << 1) ^ (((crc & 0x8000) != 0) ? 0x1021 : 0));
        }
        CRC16Table[i] = crc;
      }
      return CRC16Table;
    }
    
    // calculate the crc of a char array        
    public static char CalcCRC16(byte[] p, char[] CRC16Table) {
      char CRC;
      CRC = 0xFFFF;
      for (int ptr = 0; ptr < p.length; ptr++) {
        CRC = (char) (CRC16Table[(( (char) CRC >> 8) & 0xFF)] ^ ((char) CRC << 8) ^ p[ptr]);
      }
      return (char) CRC;
    }

Sending the data to the MyLaps decoder I always get a CRC error, so there must be an error in my conversion of the code from C to JAVA.

Can anyone help?

Oliver
  • 3
  • 1
  • 1
    Java *does* know an unsigned, 16-bit numeric type. Fortunately for you, it is `char`, which is the type you chose for the purpose. – John Bollinger Feb 22 '23 at 17:38
  • 2
    _"Sending the data to the MyLaps decoder I always get a CRC error"_ - You could start smaller by comparing the CRC tables after initialization. Are they the same? – Ted Lyngmo Feb 22 '23 at 17:42
  • Does [this](https://stackoverflow.com/a/12372331/2970947) answer your question? – Elliott Frisch Feb 22 '23 at 17:48
  • In general, for questions like this, it helps if the question includes examples (as text) of input, expected output, actual output (if any), and actual text of error messages (if any). You may edit the question. – Old Dog Programmer Feb 22 '23 at 18:07

1 Answers1

1

You have a lot of unneeded casting going on in the Java version, which is ironic because the issue appears to be at one of the places where you don't properly accommodate the type conversions involved.

Given the data types involved, this C code ...

        crc = CRC16Table[ ( ( crc >> 8 ) & 255 ) ] ^ ( crc << 8 ) ^ *p ;

... is not equivalent to this Java code ...

        CRC = (char) (CRC16Table[(( (char) CRC >> 8) & 0xFF)] ^ ((char) CRC << 8) ^ p[ptr]);

. You don't need most of those (char) casts, but the *p in the C version, a C unsigned char, is not equivalent to the p[ptr] in the Java version, a Java byte (which is signed). In both C and Java, there is an automatic promotion to int for arithmetic operands. In C, that will always extend *p with leading zero bits, but in Java, that will extend p[ptr] with leading 1 bits when its value is negative. Some of those bits are in the part of the number that will influence the result even with the logical & operations (which moot the truncation of the result to fit in a char).

You appear to want this:

        CRC = (char) (CRC16Table[(CRC >> 8) & 0xFF] ^ (CRC << 8) ^ (p[ptr] & 0xFF));
John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Hi John, you are my hero, that was the issue. Thank you SO MUCH! I had to do one small adjustment, the CRC calculation brought a syntax error, I had to change it to `CRC = (char) (CRC16Table[(CRC >> 8) & 0xFF] ^ (CRC << 8) ^ (p[ptr] & 0xFF));` Oliver – Oliver Feb 22 '23 at 18:36
  • I'm glad it helped, @Oliver, and I have edited this answer to resolve the error you describe. – John Bollinger Feb 22 '23 at 18:39