我试图连接到使用IBM BSC同步协议的旧版通信控制器,但是我无法正确获得CRC。

背景

协议本身就是在此文档中进行了很好的说明:

http://bitsavers.trailing-edge.com/pdf/ibm/datacomm/GA27-3004-2_General_Information_Binary_Synchronous_Communications_Oct70.pdf

发送通信处理器正在使用Motorola MC6852芯片。但是该芯片没有硬件crc电路,因此通讯内部有软件。可以执行crc的处理器。在这里描述了实际的通信控制器:http://storage.datormuseum.se/u/96935524/Datormusuem/Alfaskop/Alfaskop_System_41_Reference_Manual_IBM3270_Emulation.pdf

第89页及其以后描述了BSC的使用。

然后由于该设备兼容IBM 3274 C型,因此该手册适用:http://bitsavers.informatik.uni-stuttgart.de/pdf /ibm/3274/GA23-0061-1_3274_Control_Unit_Description_and_Programmers_Guide_Jan84.pdf

第159页及以后的页面与其他文档基本具有相同的信息。

实际消息

我捕获了实际通信处理器发送的两条消息。请注意,消息是用EBCDIC而不是ASCII编码的。这些是对POLL消息的响应。上面的IBM文档中的第172和175页:

32 01 6C D9 02 40 40 40 70 03 26 88

32 01 6C D9 02 40 C8 40 50 03 0D 28

从我阅读的IBM文档中,CRC算法在看到01(SOH)或02(STX)时将重置,然后累积直到看到03(ETX)。但是,SOH后跟STX不会再次在STX处重置CRC。从本质上讲,这意味着上面消息中的CRC字节是2688和0D28。有一个前导SYN(32),但由于它在SOH字符之前,因此不包括在CRC计算中。然后,用于CRC计算的消息为:
6C D9 02 40 40 40 70 03和6C D9 02 40 C8 40 50 03。 SOH不是计算的一部分,但是恰好在CRC之前的尾随ETX是CRC计算的一部分。

上面的消息是由Intel 8274芯片接收的。但是,英特尔芯片上没有进行CRC检查。

由于Intel 8274芯片包含CRC检查器/发生器,因此我应该能够生成正确格式的消息并接收消息以进行进一步检查和调查。我将稍微介绍一下这条路径,看看是否可以使用8274芯片进行接收和发送以及生成的CRC值。

8274芯片本身支持两种CRC算法。 CRC-16和CCITT CRC-16。我的理解是IBM将CRC-16与多项式X ^ 16 + X ^ 15 + X ^ 2 + 1一起使用。即8005。我看到的任何地方都没有描述使用crc的初始值。一个很好的猜测是0000h或ffffh。

情况是我想使用一个小的STM32微型控制器来处理BSC通信。我成功使用了该程序来实现与传入数据的同步并提取了格式正确的消息。但是很明显,除非我能正确获得CRC计算,否则通信将无法进行。 WIP:https://github.com/MattisLind/alfaskop_emu/tree/master/Utils/BSCGateway

CRC复仇麻烦

我尝试了crc reveng工具来计算CRC数字但我无法与上述数据匹配。我也不能使用crc reveng搜索算法。它会不断报告没有找到任何模型。

使用crc reveng将上述消息作为数据输入,多项式8005生成CRC时,不会给出相应的输出CRC数据。我尝试了CRC的几个初始值,还测试了各种选项的位顺序但不匹配。

然后我在Internet上的C语言中尝试了几种CRC算法。它们在上述消息中都给出了相同的CRC值,但都不匹配crc reveng的输出中的消息值。

应用crc reveng时很可能做错了,但我不知道是什么。

crc reveng的另一项测试

只是为了更好地了解crc reveng,我尝试了一个示例消息,其中输入数据缓冲区为初始CRC值和输出CRC值是众所周知的:https://stackoverflow.com/questions/23638939/crc-16-ibm-reverse-lookup-in-c

第一个答案中的代码马克·阿德勒(Mark Adler)提供的结果与Maxim文章中提到的结果相匹配。但是很遗憾,我无法在crc reveng中重新创建它。

请提示我做错了什么!

#1 楼

如果您知道数据,已知的CRC和未知的值(例如初始CRC值或最终XOR值),则始终可以遍历所有可能的值,并找到可以提供所需答案的值。对于32位CRC来说可能不切实际,但是对于8位和16位CRC来说,运行时间不会太长。

您至少需要两组已知数据才能可以得到更准确的值,因为许多可能的65,536个值将为一条消息提供正确的答案。但是,对于两个消息,只有很少的值会产生正确的CRC。只需循环生成两个CRC,如果两个都产生正确的结果,则打印使用的值并继续下一个。幸运的是,最后您将获得该实现所使用的正确常量-假设算法的其余部分当然是正确的!

此外,请确保您的CRC实现正确处理了字长,例如在32位架构的16位实现可能会意外地是使用高于15位的是刚刚失去了原有的16位架构。

我没有使用CRC复仇之前,但它听起来就是这样,所以我不确定为什么没有结果。在您的情况下,该算法似乎定义得很好,但是我只是对一种被证明为CRC-8的算法进行了反向工程,但实际上,它似乎更像是校验和,而不是完整的CRC算法,并且不是16位8位,所以您不能总是信任文档!如果算法在某种程度上是非标准的,则这就是为什么CRC RevEng无法将其提取的原因。

评论


谢谢您的意见!在一个叫Peter的人的帮助下,我发现第一条消息有传输错误。然后,他证明初始值为0000的多项式8005是正确的。

–马蒂斯·林德(Mattis Lind)
20年1月28日在7:54

很高兴您找到了解决方案!在这里写下您自己的答案并将其打勾作为解决方案,可能是个好主意,因此该问题被标记为已回答。

–马耳他
20年1月28日在9:27

#2 楼

解决方案

我从一个叫Peter的人那里得到了帮助。他用C语言给了我一段测试代码。CRC算法看起来与我已经尝试过的非常相似。但是重要的是他指出,第一个示例消息很可能有一点错误。



#include <stdio.h>

int crc16(unsigned char *ptr, int count)
{
    unsigned int crc;
    char i;

    crc = 0x0000;
    while (--count >= 0)
    {
        crc = crc ^ (unsigned int) *ptr++;
        i = 8;
        do
        {
            if (crc & 0x0001)
                crc = (crc >> 1) ^ 0xA001;  /* 0x8005 bit reversed */
            else
                crc = (crc >> 1);
        } while(--i);
    }
    return (crc);
}

void main()
{                   
                     /* 32  01  6C  D9  02  40  40  40  70  03  26  88 */

   unsigned char data1[] = {0x6c, 0xd9, 0x02, 0x40, 0x40, 0x40, 0x50, 0x03};

                     /* 32  01  6C  D9  02  40  C8  40  50  03  0D  28 */

   unsigned char data2[] = {0x6c, 0xd9, 0x02, 0x40, 0xc8, 0x40, 0x50, 0x03};

   printf("crc sent: 8826 computed: %4.4x\n", crc16(data1, sizeof(data1)));

   printf("crc sent: 280d computed: %4.4x\n", crc16(data2, sizeof(data2)));

   return;
}


第一条已更正的消息和第二条使用crc reveng的消息找到了算法

$ ./reveng -w 16  -s 6cd90240c84050030d28
./reveng: warning: you have only given 1 sample
./reveng: warning: to reduce false positives, give 4 or more samples
width=16  poly=0x8005  init=0x0000  refin=true  refout=true  xorout=0x0000  check=0xbb3d  residue=0x0000  name="CRC-16/ARC"
MattisMacBook:reveng-2.1.0 mattis$ ./reveng -w 16  -s 6CD90240404070032688
./reveng: warning: you have only given 1 sample
./reveng: warning: to reduce false positives, give 4 or more samples
./reveng: no models found
$ ./reveng -w 16  -s 6CD90240404050032688
./reveng: warning: you have only given 1 sample
./reveng: warning: to reduce false positives, give 4 or more samples
width=16  poly=0x8005  init=0x0000  refin=true  refout=true  xorout=0x0000  check=0xbb3d  residue=0x0000  name="CRC-16/ARC"


然后我尝试让crc reveng进行与上面提供的代码Peter相同的计算。花了好一会儿才能正确选择选项。
由于某种原因,我必须按相反的位顺序指定多项式才能使它起作用。

$ ./reveng -w 16 -P a001 -i 0000  -x 0000  -l  -d 
width=16  poly=0x8005  init=0x0000  refin=true  refout=true  xorout=0x0000  check=0xbb3d  residue=0x0000  name=(none)
$ ./reveng -w 16 -P a001 -i 0000  -x 0000  -l  -c 6CD9024040405003
2688


结论和经验教训

我从没想过接收到的数据可能有错误。那真是愚蠢。在9600 bps的连接上可能不太可能,但可能会发生。然后,我太专注于同时测试两个消息,却没有看到第二条消息实际上返回了OK CRC,尽管它交换了字节。

所以给我自己的课是:


拥有更多示例,以便可以更轻松地发现传输错误
不要以为所有消息都是正确的。
crc reveng有很多选择,乍一看可能很难正确-继续努力!

感谢所有提供帮助的人!