【发布时间】:2014-09-24 19:46:10
【问题描述】:
我正在使用一个嵌入式系统,该系统返回的 ASCII 数据包括(我认为是)modular sum checksum。我想验证这个校验和,但根据制造商的规范我无法这样做。我也无法完成相反的操作并根据描述计算相同的校验和。
来自设备的每个响应都采用以下格式:
╔═════╦═══════════════╦════════════╦════╦══════════╦═════╗
║ SOH ║ Function Code ║ Data Field ║ && ║ Checksum ║ ETX ║
╚═════╩═══════════════╩════════════╩════╩══════════╩═════╝
例子:
SOHi11A0014092414220&&FBEA
其中 SOH 是 ASCII 1。例如
#define SOH "\x01"
校验和说明如下:
校验和是一系列四个 ASCII 十六进制字符,用于检查其前面的所有字符的完整性,包括控制 人物。这四个字符代表一个 16 位二进制计数,它是清除奇偶校验位(如果启用)后消息字符的 8 位二进制表示的 2 的补码和。溢出被忽略。可以通过将四个校验和字符转换为 16 位来完成数据完整性检查 二进制数并将消息字符的 8 位二进制表示添加到它。二进制结果应该为零。
我尝试了几种不同的规范解释,包括忽略 SOH 和 & 符号,甚至函数代码。 在这一点上,无论是我对规范的解释,还是我一直用来测试的代码,我一定遗漏了一些非常明显的东西。下面你会找到一个简单的例子(数据取自live system),如果它是正确的,验证变量中的低位单词将是 0:
static void Main(string[] args)
{
unchecked
{
var data = String.Format("{0}{1}", (char) 1, @"i11A0014092414220&&");
const string checkSum = "FBEA";
// Checksum is 16 bit word
var checkSumValue = Convert.ToUInt16(checkSum, 16);
// Sum of message chars preceeding checksum
var mySum = data.TakeWhile(c => c != '&').Aggregate(0, (current, c) => current + c);
var validate = checkSumValue + mySum;
Console.WriteLine("Data: {0}", data);
Console.WriteLine("Checksum: {0:X4}", checkSumValue);
Console.WriteLine("Sum of chars: {0:X4}", mySum);
Console.WriteLine("Validation: {0}", Convert.ToString(validate, 2));
Console.ReadKey();
}
}
编辑
虽然@tinstaafl 提供的解决方案适用于这个特定的示例,但它在提供更大的记录时不起作用,如下所示:
SOHi20100140924165011000007460904004608B40045361000427DDD6300000000427C3C66000000002200000745B4100045B3D8004508C00042754B900000000042774D8D0000000033000007453240004531E000459F5000420EA4E100000000427B14BB000000005500000744E0200044DF4000454AE000421318A0000000004288A998000000006600000744E8C00044E7200045469000421753E600000000428B4DA50000000 && P>
BA6C
理论上,您可以不断增加/减少字符串中的值,直到校验和匹配,碰巧使用字符 1 而不是 ASCII SOH 控制字符给了它正确的值,在这种情况下是巧合。
【问题讨论】:
-
功能代码/数据字段的长度是否固定?是否有任何 ASCII 控制字符分隔输入?对于第二个例子,是SOH的前导1部分,还是功能代码的开始?
-
功能码的长度看起来是固定的,数据字段的长度取决于功能码。有些还具有可变数量的固定列。我已经编辑了示例并删除了消息开头的 1 并将其替换为 SOH。我把 1 放在那里是为了证明用 1 替换 SOH 只是第一个示例中的巧合。
-
我强烈怀疑规范不完整或有错误。 8 位无符号二进制的最大值是 255。2 的补码应该是它的负值。但是校验和值小于 -255,因此丢弃溢出的 8 位和,当添加到校验和值时,永远不会等于 0。
-
我也在认真考虑这种可能性,尽管我希望我的代码中有一个简单的错误;-)。如果我以一种或另一种方式提出答案,我会发布它。
-
经过更多研究,我认为这些设备有很多问题。我发现字段长度不匹配的情况(从分钟字段中删除尾随零等)。有时它甚至会将丢失的零添加到最后。我的猜测是校验和是这里的问题,而不是我的代码。