【翻译】带CRC校验的XModem协议

导论

Xmodem协议是一种很久之前就被提出的协议,其作为一种简单的工具,使得两台电脑可以相互通讯。由于其具有的半双工、128字节长度包数据(译者注:对于包数据长度不足128字节的情况,使用0x1A填充到128字节,一般发生于传输的最后一个数据包)、ACK/NACK应答以及CRC校验这些机制,在很多应用场合中都能见到Xmodem协议的身影。实际上,现在个人计算机上的大多数通信包都有一个xmodem协议可供用户使用。

工作原理

Xmodem是一种半双工的通讯协议。每当接收者接收到一个数据包,其将会选择应答(ACK)或者不应答(NAK)这个数据包。与其他常见的通讯协议一样,更加稳健的16位CRC校验被用于校验Xmodem传输的数据的有效性(译者注:并不是所有的Xmodem协议都使用CRC校验,更老的版本使用的是简单的8位累加和校验,在90年代修订了一次标准,改为了16位CRC校验)。Xmodem可以看作是一种由接收端驱动的协议。也就是说,接收端发送一个初始化字符\'C\'到发送端来告知已经准备好以CRC校验的方式接收数据。之后,发送端会发送一个133字节的数据包,接收端校验收到的数据包并且回应一个应答(ACK)或者非应答(NAK),根据接收端的应答,发送端会决定发送下一个数据包还是重新发送上一次的数据包。这个过程会一直进行,直到接收端收到EOT之后发送一个ACK到发送端。在进行握手之后,接收端通过回应ACK或NAK到发送端来控制数据流的传输。

表1:XmodemCRC数据包结构

符号定义

以下符号定义被用于协议的流控制。

XmodemCRC数据包的字节1的值只能是SOH、EOT、CAN或者ETB中的一个,除此之外的任何值都应当被视为一个错误。字节2和字节3组成带校验和(checksum)功能的包序号,这两位相加起来应该永远等于0xFF。请记住,包序号从1开始,并且在大于255个数据包需要接收时溢出为0。字节4到字节131组成数据部分,它们可以是任意数据。字节132和133组成了16位CRC校验。CRC的高位为字节132。CRC校验只计算了数据部分,即字节4到字节131。

同步方法

接收端通过发送ASCII码表中的字符\'C\'(0x43)到发送端来指明希望通过CRC方法来进行数据校验。在发送初始字符\'C\'之后,接收端等待3秒钟直到等待超时或者缓冲区满标志位被置位。如果接收端等待超时了,另一个\'C\'会被发送给发送端并且再次进行一次时长3秒的等待。这个流程会一直进行直到接收端收到了一个完整的133字节的数据包。

接收端注意事项

在以下情况下,接收端应该回应非应答(NAK):

  1. 任何字节出现帧错误
  2. 任何字节出现溢出错误
  3. 收到重复序号的包
  4. CRC校验错误
  5. 接收超时(未在1秒钟内接收完一个数据包)

对于任何非应答(NAK),发送端将会重发上一次的数据包。情况1和情况2应该被认为是严重的硬件错误。确保发送端和接收端使用同样的波特率、开始位和停止位。情况3通常发生于发送端收到的应答(ACK)发生了混淆,于是发送端重发了上一次的数据包。情况4会在存在干扰的环境下出现,这个问题应该会在接收端非应答(NAK)发送端后被纠正(译者注:即发送端会重发校验不对的数据包)。

收发示例

简易的CRC校验计算代码

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

    crc = 0;
    while (--count >= 0)
    {
        crc = crc ^ (int) *ptr++ << 8;
        i = 8;
        do
        {
            if (crc & 0x8000)
                crc = crc << 1 ^ 0x1021;
            else
                crc = crc << 1;
        } while(--i);
    }
    return (crc);
}