【问题标题】:Need Assistance in Calculating Checksum在计算校验和时需要帮助
【发布时间】:2013-05-29 20:11:32
【问题描述】:

我正在使用 Python 开发家庭自动化系统 (ElkM1) 的接口。我在下面的 C# 中有示例代码,显然正确地计算了向该系统发送消息时所需的校验和。我将下面的 python 代码放在一起,但它似乎没有返回正确的值。

根据文档,消息的校验和需要是 mod256 中消息的 ASCII 值的总和,然后作为 2s 补码。从他们的手册中:“这是消息中所有字符的 ASCII 值的模 256 和的十六进制二进制补码,不包括校验和本身和消息末尾的 CR-LF 终止符。允许的字符是 ASCII 0-9和大写A-F。当所有字符都添加到校验和时,值应该等于0。”

供应商有一个工具可以计算正确的校验和。作为测试数据,我一直在使用“00300005000”,它应该返回校验和 74

我的代码返回 18

提前致谢。

我的代码(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]

他们的代码 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");
}

【问题讨论】:

    标签: python checksum twos-complement


    【解决方案1】:

    FWIW,这是 C# 代码到 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')
    

    它输出的消息是E8,显示的消息与您的代码和 C# 代码都不同。鉴于手册中的描述并手动进行计算,我看不出他们的答案怎么可能是74。你怎么知道这是正确答案?

    在看到 Mark Ransom 的 C# 代码确实返回 E8 的评论后,我花了一些时间调试您的 Python 代码并找出为什么它不会产生相同的结果。一个问题是它没有正确计算代码中注释#inverse 的二进制补码。至少有几种方法可以正确地做到这一点。

    第二个问题是hex() 函数处理负数的方式不是您所期望的。在这种情况下,使用-24 二进制补码会产生-0x18,而不是0xffe8 或类似的东西。这意味着只取大写结果的最后两个字符是不正确的。一个非常简单的方法是使用% 字符串插值运算符将值的低字节转换为大写十六进制。这是您的函数的工作版本:

    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)
    

    更 Pythonic(和更快)的实现将是这样的单行,它利用内置的 sum() 函数:

    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)
    

    【讨论】:

    • 使用 sum() 函数(并避免使用名为 'sum' 的变量):
       def calc_checksum(s): checksum = -(sum([ord(c) for c in s]) % 256) return '%2X' % (checksum & 0xFF) 
      ...但我得到与@martineau相同的结果。
    • 谢谢@Mark,很高兴知道有类似ideone.com 的东西可用。
    猜你喜欢
    • 2015-10-28
    • 1970-01-01
    • 2012-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多