2014-09-24 62 views
3

我正在使用一个嵌入式系统,该系统返回包含(我相信是)的ASCII数据。我想验证这个校验和,但是我根据制造商的规格一直无法这样做。我也无法完成相反的操作,并根据描述计算相同的校验和。在c中验证模块化总和校验和#

从器件中的每个响应是以下格式:

╔═════╦═══════════════╦════════════╦════╦══════════╦═════╗ 
║ SOH ║ Function Code ║ Data Field ║ && ║ Checksum ║ ETX ║ 
╚═════╩═══════════════╩════════════╩════╩══════════╩═════╝ 

实施例:

SOHi11A0014092414220&&FBEA 

哪里SOH是ASCII 1例如

#define SOH "\x01" 

校验和的说明如下:

校验和是一系列四个ASCII十六进制字符,其提供上的所有字符的完整的检查它之前,包括控制 个字符。这四个字符表示一个16位二进制计数,它是奇偶校验位(如果使能)被清除后,消息字符的8位二进制表示的二进制补码总和。溢出被忽略。数据完整性检查可以通过将四个校验和字符转换为16位的 二进制数字并将消息字符的8位二进制表示添加到它来完成。二进制结果应该为零。

我试过了一些对规范的不同解释,包括忽略SOH以及和号,甚至函数代码。 在这一点上,我必须在我对规范的解释或我一直用来测试的代码中忽略一些非常明显的东西。下面你会发现一个简单的例子(数据来自现场系统获取),如果它是正确的,在验证变量的低位字是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工作所提供的解决方案,提供更大的记录时,它不起作用,如下面的:

SOHi20100140924165011000007460904004608B40045361000427DDD6300000000427C3C66000000002200000745B41000 45B3D8004508C00042754B900000000042774D8D0000000033000007453240004531E000459F5000420EA4E100000000427B14BB000000005500000744E0200044DF4000454AE000421318A0000000004288A998000000006600000744E8C00044E7200045469000421753E600000000428B4DA50000000 & &

BA6C 

理论上你可以不断递增/递减字符串中的值,直到校验和匹配,它只是碰巧使用字符1,而不是ASCII SOH控制字符给它恰到好处的价值,在这种情况下是巧合。

+0

功能代码/数据字段的长度是否固定? 是否有任何ASCII控制字符分隔输入? 第二个例子是SOH的主要部分,还是功能代码的开始? – user1112560 2014-09-25 00:20:45

+0

功能代码的长度似乎是固定的,数据字段的长度取决于功能代码。有些还具有可变数量的固定列。我编辑了这个示例,并删除了在消息开头的那个1,并用SOH替换了它。我在那里说明,用1代替SOH只是第一个例子中的巧合。 – dpeterson 2014-09-25 13:18:10

+0

我强烈怀疑规格不完整或出现错误。 8位无符号二进制的最大值是255. 2的补码应该是负值。然而,校验和值小于-255,因此当添加到校验和值时,丢弃溢出的8位总和永远不会等于0. – tinstaafl 2014-09-25 17:29:34

回答

1

不知道这是否正是您要查找的内容,而是通过使用SOH的整数1而不是1的char值,取所有字符的总和并将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(); 
+0

不幸的是,似乎只适用于这个特殊的例子,这是这种校验和的弱点之一。我将编辑我的问题以提供一个以1代替它不起作用的例子。 – dpeterson 2014-09-24 22:01:45