ZMODEM 接收端实现源码解析:以 rz 示例为例

发布于:2025-07-06 ⋅ 阅读:(14) ⋅ 点赞:(0)



ZMODEM 接收端实现源码解析:以 rz 示例为例

在嵌入式和串口通信领域,ZMODEM 协议被广泛用于串口文件传输,尤其适用于固件升级、配置传输等场景。相比 XMODEM 和 YMODEM,ZMODEM 拥有流式传输、自动开始、断点续传等优势,是工业环境中较为成熟的一种协议。

本文将通过一份 C 语言编写的 ZMODEM 接收端示例源码,解析其实现逻辑和核心机制,为开发者提供移植和应用该协议的参考。


一、项目概述

该程序是一个模拟 rz 命令功能的示例,运行在类 UNIX 系统中,通过文件接口访问串口设备,实现了较完整的 ZMODEM 协议接收流程。它主要包括以下功能:

  • 等待远程 ZMODEM 发送方启动传输;
  • 解析协议帧(ZRQINIT、ZFILE、ZDATA、ZEOF、ZFIN 等);
  • 支持文件头识别和数据写入;
  • 实现错误检测与自动重传(通过 ZRPOS);
  • 支持传输取消与中断处理。

二、结构设计与模块划分

1. 串口收发接口

程序将串口抽象为标准文件流 FILE *com,并实现了 zm_recv()zm_send(),用于 ZMODEM 协议栈内部调用:

ZRESULT zm_recv() {
  uint8_t result;
  if (fread(&result, 1, 1, com) == 1)
    return result;
  else
    return CLOSED;
}

ZRESULT zm_send(uint8_t chr) {
  int result = fputc((char)chr, com);
  return (result == EOF) ? CLOSED : OK;
}

2. 串口初始化

串口设备通过命令行传入(如 /dev/ttyUSB0),程序通过 fopen() 打开并取消缓冲:

static FILE* init_com(int argc, char **argv) {
    FILE *com = fopen(argv[1], "wb+");
    setvbuf(com, NULL, _IONBF, 0); // 禁用缓冲
    return com;
}

三、ZMODEM 协议核心流程解析

主流程位于 main() 函数中,包含等待初始化、接收头帧、数据帧、终止确认等。

1. 等待传输初始化

程序首先调用 zm_await("rz\r", ...) 等待对端开始 rz 传输过程:

if (zm_await("rz\r", (char*)rzr_buf, 4) == OK) {
    // 进入主接收循环
}

2. 接收 ZMODEM 帧头

主循环中调用 zm_await_header() 获取协议帧头并解析:

ZRESULT result = zm_await_header(&hdr);
switch (hdr.type) {
    case ZRQINIT:
    case ZEOF:
        zm_send_flags_hdr(ZRINIT, CANOVIO | CANFC32, 0, 0, 0);
        break;

3. 文件头(ZFILE)处理

当接收到 ZFILE 时,调用 zm_read_data_block() 获取文件名,并打开写入文件:

result = zm_read_data_block(data_buf, &count);
out = fopen((char*)data_buf, "wb");
zm_send_pos_hdr(ZRPOS, received_data_size);

4. 数据帧(ZDATA)接收

进入 ZDATA 状态后,程序进入子循环读取数据块,识别结束符号(如 CRCECRCGCRCQCRCW):

while (true) {
    result = zm_read_data_block(data_buf, &count);
    fwrite(data_buf, count - 1, 1, out);
    received_data_size += (count - 1);

    if (result == GOT_CRCW || result == GOT_CRCQ) {
        zm_send_pos_hdr(ZACK, received_data_size);
    }
}

5. 异常与错误处理

如果 CRC 校验失败或其他错误,通过 ZRPOS 回应远程重发:

result = zm_send_pos_hdr(ZRPOS, received_data_size);
goto startframe;

四、协议帧类型说明

帧类型 含义
ZRQINIT 初始化请求
ZRINIT 初始化响应
ZFILE 文件信息头(文件名)
ZDATA 数据块
ZEOF 文件结束
ZFIN 会话结束
ZACK 传输确认
ZNAK 错误响应
ZRPOS 请求重传

五、功能总结

本示例实现了以下 ZMODEM 协议关键流程:

  • 接收文件名并创建本地文件;
  • 解析并写入文件数据;
  • 错误检测和自动请求重传;
  • 传输终止与确认;
  • 支持 ASCII、二进制等多种传输模式(默认使用 ZCBIN);

六、适用与移植建议

该程序适合作为以下用途:

  • 在 PC 上调试串口文件传输功能;
  • 嵌入式 Bootloader 文件接收功能的参考实现;
  • 移植到 STM32、RT-Thread 等裸机/RTOS 系统中(需替换 FILE 接口为串口驱动);
  • 与上位机串口工具(如 XShell、SecureCRT)搭配使用,快速测试串口传输稳定性。

移植建议:

  • 用平台串口驱动替代 fread/fputc
  • 用 Flash 或 FatFs 替代 fopen/fwrite
  • 精简数据缓存,控制内存占用;
  • 加入超时处理和断电保护机制;
  • 可选支持 YMODEM 做替代方案,结构更简单。

七、结语

本文通过对一份基于标准 C 的 ZMODEM 接收程序进行解析,展示了其实现机制与协议流程。作为串口文件传输的重要协议,ZMODEM 在嵌入式系统中具有重要价值,理解其底层工作原理有助于开发更加可靠和通用的通信方案。

如需实现嵌入式串口升级或远程配置功能,ZMODEM 是一个值得参考与实现的通信协议。