0
votes

I am using simpleBGC gimbal controller from Basecam electronics. The controller has a serial API for communication which requires the calculation of crc16 checksum for the commands sent to the controller(https://www.basecamelectronics.com/file/SimpleBGC_2_6_Serial_Protocol_Specification.pdf) (page 3)

I want to send the reset command to the controller which has the following format:

Header: {start char: '$', command id: '114', payload size: '3', header checksum : '117'}

Payload: {3,0,0} (3 bytes corresponding to reset options and time to reset)

crc16 checksum : ? (using polynomial 0x8005 calculated for all bytes except start char)

The hex representation of my command is: 0x24720375030000 and I need to find crc16 checksum for 0x720375030000. I used different crc calculators but the controller is not responding to the command and I assume that crc checksum is not correct. To find correct crc16 checksum I sent every possible combination of crc16 checksum and found out that the controller responds when checksum is '7b25'. so the correct command in hex is : "24 720375030000 7b25". But this checksum 7b25 does not correspond to the polynomial 0x8005. How can I find the correct polynomial or crc16 calculation function?

1
Link for Basecam electronics serial API manual: basecamelectronics.com/serialapi - Owais

1 Answers

0
votes

Did you try the code in the appendix of the document you linked? It works fine, and produces 0x257b for the CRC of your example data. That is then written in the stream in little-endian order, giving the 7b 25 you are expecting.

Here is a simpler and faster C implementation than what is in the appendix:

#include <stddef.h>

// Return a with the low 16 bits reversed and any bits above that zeroed.
static unsigned rev16(unsigned a) {
    a = (a & 0xff00) >> 8 | (a & 0x00ff) << 8;
    a = (a & 0xf0f0) >> 4 | (a & 0x0f0f) << 4;
    a = (a & 0xcccc) >> 2 | (a & 0x3333) << 2;
    a = (a & 0xaaaa) >> 1 | (a & 0x5555) << 1;
    return a;
}

// Implement the CRC specified in the BASECAM SimpleBGC32 2.6x serial protocol
// specification. Return crc updated with the length bytes at message. If
// message is NULL, then return the initial CRC value. This CRC is like
// CRC-16/ARC, but with the bits reversed.
//
// This is a simple bit-wise implementation. Byte-wise and word-wise algorithms
// using tables exist for higher speed if needed. Also this implementation
// chooses to reverse the CRC bits as opposed to the data bits, as done in the
// specficiation appendix. The CRC only needs to be reversed once at the start
// and once at the end, whereas the alternative is reversing every data byte of
// the message. Reversing the CRC twice is faster for messages with length
// greater than two bytes.
unsigned crc16_simplebgc(unsigned crc, void const *message, size_t length) {
    if (message == NULL)
        return 0;
    unsigned char const *data = message;
    crc = rev16(crc);
    for (size_t i = 0; i < length; i++) {
        crc ^= data[i];
        for (int k = 0; k < 8; k++)
            crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1;
    }
    return rev16(crc);
}

#include <stdio.h>

// Example usage of crc_simplebgc(). A CRC can be computed all at once, or with
// portions of the data at a time.
int main(void) {
    unsigned crc = crc16_simplebgc(0, NULL, 0);         // set initial CRC
    crc = crc16_simplebgc(crc, "\x72\x03\x75", 3);      // first three bytes
    crc = crc16_simplebgc(crc, "\x03\x00\x00", 3);      // remaining bytes
    printf("%04x\n", crc);                              // prints 257b
    return 0;
}