我正在使用Python的家庭自动化系统(ElkM1)界面。我在下面的C#中有示例代码,显然正确地计算了向此系统发送消息时所需的校验和。我把下面的python代码放在一起,但似乎没有返回正确的值。
根据文档,消息的校验和需要是mod256中消息的ASCII值的总和,然后作为2s补码。从他们的手册:“这是消息中所有字符的ASCII值的模数256和的十六进制二进制补码,不包括校验和本身和消息末尾的CR-LF终止符。允许的字符是ASCII 0-9和大写AF。当所有字符都添加到校验和时,该值应该等于0.“
供应商有一个工具可以计算正确的校验和。作为测试数据,我一直在使用'00300005000',它应该返回74的校验和
我的代码返回18
提前致谢。
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]
private string checksum(string s)
{
int sum = 0;
foreach (char c in s)
sum += (int)c;
sum = -(sum % 256);
return ((byte)sum).ToString("X2");
}
答案 0 :(得分:3)
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)