Search code examples
javascriptbluetooth-lowenergychecksum

Implement CRC8 checksum with JS


Already tried CRC8 but I wasn't able to get the correct checksum.

Does anyone have an idea of how this checksum could be generated using JS ?


Solution

  • This proved to be a very tricky one to solve, but I think I have a solution. It's a JavaScript port (mostly) of the Java. I did some simplifying of the code to eliminate the things that didn't seem to affect the answer.

    First I had to export the hex equivalent of the CRC8_DATA in your Java program. I achieved this using just a simple bytesToHex routine I found here (this part is in Java):

    System.out.print(bytesToHex(CRC8_DATA));
    ...
    private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = HEX_ARRAY[v >>> 4];
            hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
        }
        return new String(hexChars);
    }
    

    Once I had this table, I just converted the Java code into JavaScript, to arrive at this:

    var CRC8_DATA = '005EBCE2613FDD83C29C7E20A3FD1F419DC3217FFCA2401E5F01E3BD3E6082DC237D9FC1421CFEA0E1BF5D0380DE3C62BEE0025CDF81633D7C22C09E1D43A1FF4618FAA427799BC584DA3866E5BB5907DB856739BAE406581947A5FB7826C49A653BD987045AB8E6A7F91B45C6987A24F8A6441A99C7257B3A6486D85B05E7B98CD2306EEDB3510F4E10F2AC2F7193CD114FADF3702ECC92D38D6F31B2EC0E50AFF1134DCE90722C6D33D18F0C52B0EE326C8ED0530DEFB1F0AE4C1291CF2D73CA947628ABF517490856B4EA6937D58B5709EBB536688AD495CB2977F4AA4816E9B7550B88D6346A2B7597C94A14F6A8742AC896154BA9F7B6E80A54D7896B35';
    
    function strToArr(str) {
      var arr = str.match(/[0-9a-f]{2}/ig); // convert into array of hex pairs
      arr = arr.map(x=> parseInt(x, 16)); // convert hex pairs into ints (bytes)
      return arr;
    }
    
    CRC8_DATA = strToArr(CRC8_DATA);
    
    function calculateCRC8(bArr) {
      var i = 1;
      var i2 = bArr.length - 1;
      var b = 0;
      while (i <= i2) {
        b = CRC8_DATA[(b ^ bArr[i]) & 255];
        i++;
      }
      return b;
    }
    
    function calcFromString(str) {
      // convert from string to "byte" array
      var byte_array = strToArr(str);
      var checksum = calculateCRC8(byte_array)
      console.log(str, checksum.toString(16));
    }
    
    calcFromString('02FD 1000 2322 4978 0140 00AF 6000 0000 0000');
    calcFromString('02FD 1000 D82E 4F76 0189 00AF FA14 0000 0000');

    The original Java is starting with i=1, so it's actually not including the first byte in the checksum calculation. That's probably one of the reasons why a lot of the JavaScript libraries weren't giving the same answer.

    I went back and compared this with this online CRC calculator. When eliminating the first byte (0x02), I was able to get equivalent results using CRC-8/MAXIM;DOW-CRC.

    I was not able to get the original fiddle working though, even after dropping the first byte and changing the polynomial to match the one from that website. Some of the other options must be different as well.