【问题标题】:Verifying modular sum checksum in c#在 C# 中验证模和校验和
【发布时间】: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。
  • 我也在认真考虑这种可能性,尽管我希望我的代码中有一个简单的错误;-)。如果我以一种或另一种方式提出答案,我会发布它。
  • 经过更多研究,我认为这些设备有很多问题。我发现字段长度不匹配的情况(从分钟字段中删除尾随零等)。有时它甚至会将丢失的零添加到最后。我的猜测是校验和是这里的问题,而不是我的代码。

标签: c# ascii checksum


【解决方案1】:

不确定这是否正是您要查找的内容,但通过对 SOH 使用整数 1 而不是 char 值 1,取所有字符的总和并将 validate 变量转换为16位整数,我能够验证等于0:

var data = (@"1i11A0014092414220&&");
const string checkSum = "FBEA";

// Checksum is 16 bit word
var checkSumValue = Convert.ToUInt16(checkSum, 16);

// Sum of message chars preceeding checksum
var mySum = data.Sum<char>(c => c);
var validate = (UInt16)( 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();

【讨论】:

  • 不幸的是,这似乎只适用于这个特定的例子,这是这种校验和的弱点之一。我将编辑我的问题以提供一个示例,说明用 1 替换它不起作用的地方。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-20
  • 2020-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多