Need Assistance in Calculating Checksum

17,762

FWIW, here's a literal translation of the C# code into Python:

def calc_checksum(s):
    sum = 0
    for c in s:
        sum += ord(c)
    sum = -(sum % 256)
    return '%2X' % (sum & 0xFF)

print calc_checksum('00300005000')

It outputs is E8 for the message shown which is different from both your and the C# code. Given the description in the manual and doing the calculations by hand, I don't see how their answer could be 74. How do you know that's the correct answer?

After seeing Mark Ransom's comment that the C# code does indeed return E8, I spent some time debugging your Python code and found out why it doesn't produce the same result. One problem is that it doesn't calculate the two's complement correctly on the line with the comment #inverse in your code. There's at least a couple of ways to do that correctly.

A second problem is way the hex() function handles negative numbers is not what you'd might expect. With the -24 two's complement in this case it produces -0x18, not 0xffe8 or something similar. This means that just taking the last two characters of the uppercased result would be incorrect. An really easy way to do that is just convert the lower byte of the value to uppercase hexadecimal using the % string interpolation operator. Here's a working version of your function:

def calc_checksum(string):
    '''
    Calculates checksum for sending commands to the ELKM1.
    Sums the ASCII character values mod256 and takes
    the Twos complement.
    '''
    sum = 0

    for i in range(len(string)):
        sum = sum + ord(string[i])

    temp = sum % 256  # mod256
#    rem = (temp ^ 0xFF) + 1  # two's complement, hard way (one's complement + 1)
    rem = -temp  # two's complement, easier way
    return '%2X' % (rem & 0xFF)

A more Pythonic (and faster) implementation would be a one-liner like this which makes use of the built-in sum() function:

def calc_checksum(s):
    """
    Calculates checksum for sending commands to the ELKM1.
    Sums the ASCII character values mod256 and returns
    the lower byte of the two's complement of that value.
    """
    return '%2X' % (-(sum(ord(c) for c in s) % 256) & 0xFF)
Share:
17,762
Admin
Author by

Admin

Updated on June 04, 2022

Comments

  • Admin
    Admin almost 2 years

    I am working on an interface in Python to a home automation system (ElkM1). I have sample code in C# below which apparently correctly calculates the checksum needed when sending messages to this system. I put together the python code below but it doesn't appear to be returning the correct value.

    According to the documentation the checksum of the message needs to be the sum of the ASCII values of the message in mod256 then taken as 2s complement. From their manual: "This is the hexadecimal two‟s complement of the modulo-256 sum of the ASCII values of all characters in the message excluding the checksum itself and the CR-LF terminator at the end of the message. Permissible characters are ASCII 0-9 and upper case A-F. When all the characters are added to the Checksum, the value should equal 0."

    The vendor has a tool which will calculate the correct checksum. As test data I have been using '00300005000' which should return a checksum of 74

    My code returns 18

    Thanks in advance.

    My Code (Python)

    def calc_checksum (string):
        '''
        Calculates checksum for sending commands to the ELKM1.  
        Sums the ASCII character values mod256 and takes
        the Twos complement
        '''
        sum= 0
    
        for i in range(len(string)) :
            sum = sum + ord(string[i])
    
        temp = sum % 256  #mod256
        rem = temp ^ 256  #inverse
        cc1 = hex(rem)
        cc = cc1.upper()
        p=len(cc)
        return cc[p-2:p]
    

    Their Code C#:

    private string checksum(string s)
    {
        int sum = 0;
        foreach (char c in s)
            sum += (int)c;
    
        sum = -(sum % 256);
    
        return ((byte)sum).ToString("X2");
    }