/* TUF-2000M User Manual 40 01 03 00 00 00 0A C5 CD (hex) Unit Function start REG Numbers of REGs Check-sum While under the MODBUS-ASCII format, the command could be :01030000000AF2(CR and LF) */
paste the codes into the box below. It works out the CRC as each byte is added.
If the calculated CRC != 0 , append a CRC. If it includes the CRC, the calculated CRC should equal zero
Examples: 0x01,0x03,0x00,0x02,0x00,0x02, 0x65,0xCB 0x01,0x03,0x04,0x01,0xe6,0xff,0x9f, 0x1b,0xA0
output
https://how2electronics.com/modbus-rtu-with-raspberry-pi-pico-micropython/
def calculate_crc(frame):
    crc = 0xFFFF
    for pos in frame:
        crc ^= pos
        for _ in range(8):
            if crc & 0x0001:
                crc >>= 1
                crc ^= 0xA001
            else:
                crc >>= 1
    return crc
 
def construct_modbus_request(address, function, start_high, start_low, count_high, count_low):
    frame = [address, function, start_high, start_low, count_high, count_low]
    crc = calculate_crc(frame)
    frame.append(crc & 0xFF)         # CRC low byte
    frame.append((crc >> 8) & 0xFF)  # CRC high byte
    return bytes(frame)
CRC16/MODBUS
x¹⁶ + x¹⁵ + x² + 1
16	0x8005	0xFFFF	0x0000	true	true	Used in Modbus industrial protocol
uint16_t calc(uint8_t *packet, uint8_t size)
{
    uint16_t crc_polynome = 0xa001;
    uint16_t crc = 0xffff;
    for (uint8_t j = 0; j < size; j++)
    {
        crc ^= packet[j];
        for (uint8_t i = 0; i < 8; i++)
        {
            if (crc & 0x1)
            {
                crc >>= 1; 
                crc ^= crc_polynome;
            } 
            else 
            { 
                crc >>= 1;
            }
        }
    }
    return crc;
}
Address Code	Function Code	Initial Address	Data Length	Check Code Low	Check Code High
0x01	0x03	0x00 0x02	0x00 0x02	0xC4	0x08
Response Frame (hexadecimal): (For example, the temperature is -9.7°C and the humidity is 48.6%RH)
Address Code	Function Code	Number of Valid Bytes	Humidity Value	Temperature Value	Check Code Low	Check Code High
0x01	0x03	0x04	0x01 E6	0xFF 0x9F	0x1B	0xA0
/*
uint16_t calc(uint8_t *packet, uint8_t size)
{
    uint16_t crc_polynome = 0xa001;
    uint16_t crc = 0xffff;
    for (uint8_t j = 0; j < size; j++)
    {
        crc ^= packet[j];
        for (uint8_t i = 0; i < 8; i++)
        {
            if (crc & 0x1)
            {
                crc >>= 1; 
                crc ^= crc_polynome;
            } 
            else 
            { 
                crc >>= 1;
            }
        }
    }
    return crc;
}
*/