Search code examples
pythonbinaryhexbit-manipulationchecksum

Calculating a checksum, using the most and least significant bits differently


I'm trying to calculate a checksum, and I have to admit my binary manipulation knowlege is failing me.

If anyone could help with the below (and improve the title of this question) I'd be most grateful.

(I've tried quite a lot of things, but I think I'm just not going about it correctly)

A previous question I asked is here, but the technique is different, I think - How to build byte array frame and calculate checksum

Documentation below:

To avoid the checksum coinciding with any of the control bytes (0x02 and 0x03), the checksum is divided into two bytes. In the first byte the four least significant bits are introduced, and the four most significant ones in the second.

Example:

Checksum calculation of the following command:

STX 0x02
Filler1 0x30
Filler2 0x30
Address 0x81
Type 0x56 “V”
Tray 0x8B
Belt 0x82
Checksum1 0xF6
Checksum2 0x4F
ETX 0x03

Add the values of every byte previous to the checksum. The result is obtained as an unsigned char.

Checksum = 0x02+0x30+0x30+0x81+0x56+0x8B+0x82 = 0x46

Set the four most significant bits to “1” using OR operator, forming Checksum1, where the four least significant bits of Checksum are stored.

Checksum1 = Checksum | 0xF0 = 0x46 | 0xF0 = 0xF6

Change the four least significant bits to “1” using OR operator, forming Checksum1, where the four most significant bits of Checksum are stored.

Checksum2 = Checksum | 0x0F = 0x46 | 0x0F = 0x4F

Additional

def print_bytes(bytes):
    print("\n" + " ".join("\\x%02X" % v for v in bytes))

frame = bytearray([0x02,0x30,0x30,0x81,0x56,0x8B,0x82])

print_bytes(sum(frame).to_bytes(2, "little"))

\x46 \x02

Solution

  • The result is obtained as an unsigned char.

    This means that you must only use the 8 least significant bits to calculate.

    >>> (0x02 + 0x30 + 0x30 + 0x81 + 0x56 + 0x8b + 0x82)
    582
    >>> (0x02 + 0x30 + 0x30 + 0x81 + 0x56 + 0x8b + 0x82) & 0xff
    70
    

    And then within those 8 bits you need to set the 4 most and least significant bits.

    >>> 70 | 0xf0
    246
    >>> 70 | 0x0f
    79
    

    This then results in 0xf6 and 0x4f as shown in the checksum bytes.