跳转至

ymodem文件传输(Air780EPM不支持)

一、Ymodem协议概述

Ymodem是一种基于串行通信的文件传输协议,由Chuck Forsberg于1980年代初期在Xmodem协议基础上改进而来。其设计目标是解决Xmodem在大文件传输效率低(仅支持128字节数据块)、缺乏批处理能力等问题,通过引入1024字节数据块和批量文件传输机制,显著提升传输效率与可靠性,成为早期嵌入式系统和计算机间文件交换的核心技术之一。

1.1 核心特性

特性 说明
数据块大小 支持 128 字节(SOH 模式)和 1024 字节(STX 模式)
错误检测 使用 CRC-16 循环冗余校验,校验范围包含数据块内容
批处理传输 可一次性发送多个文件,支持文件名和文件大小元数据传递
流量控制 通过 ACK/NAK 机制实现自动重传,防止数据溢出
填充规则 数据不足时用 0x1A 填充,结束帧用 0x00 填充
特性 说明
数据块大小 支持 128 字节(SOH 模式)和 1024 字节(STX 模式)
错误检测 使用 CRC-16 循环冗余校验,校验范围包含数据块内容
批处理传输 可一次性发送多个文件,支持文件名和文件大小元数据传递
流量控制 通过 ACK/NAK 机制实现自动重传,防止数据溢出
填充规则 数据不足时用 0x1A 填充,结束帧用 0x00 填充

1.2 帧格式说明

1.2.1 起始帧(133 字节)

字段 字节数 描述
SOH 1 0x01 起始符(固定为 SOH)
块编号 1 0x00 固定为 00
块编号反码 1 0xFF 块编号的二进制反码
文件名 变长 foo.bin 以 0x00 结尾的字符串
文件大小 变长 1024 十进制数值 + 0x00 结尾
填充区 剩余 0x00 补满至 128 字节
CRC 校验码 2 CRCH CRCL 高字节在前,低字节在后
字段 字节数 描述
SOH 1 0x01 起始符(固定为 SOH)
块编号 1 0x00 固定为 00
块编号反码 1 0xFF 块编号的二进制反码
文件名 变长 foo.bin 以 0x00 结尾的字符串
文件大小 变长 1024 十进制数值 + 0x00 结尾
填充区 剩余 0x00 补满至 128 字节
CRC 校验码 2 CRCH CRCL 高字节在前,低字节在后

1.2.2 数据帧(1029/133 字节)

字段 字节数 描述
STX/SOH 1 0x02/0x01 1024 字节用 STX,128 用 SOH
块编号 1 0x01 从 01 递增
块编号反码 1 0xFE 块编号的二进制反码
数据区 1024/128 原始数据 不足时用 0x1A 填充
CRC 校验码 2 CRCH CRCL 校验数据区内容
字段 字节数 描述
STX/SOH 1 0x02/0x01 1024 字节用 STX,128 用 SOH
块编号 1 0x01 从 01 递增
块编号反码 1 0xFE 块编号的二进制反码
数据区 1024/128 原始数据 不足时用 0x1A 填充
CRC 校验码 2 CRCH CRCL 校验数据区内容

1.2.3 结束帧(133 字节)

字段 字节数 描述
SOH 1 0x01 固定为 SOH
块编号 1 0x00 固定为 00
块编号反码 1 0xFF 固定为 FF
填充区 128 0x00 全 0 填充
CRC 校验码 2 0x0000 固定为 0
字段 字节数 描述
SOH 1 0x01 固定为 SOH
块编号 1 0x00 固定为 00
块编号反码 1 0xFF 固定为 FF
填充区 128 0x00 全 0 填充
CRC 校验码 2 0x0000 固定为 0

1.3 控制字符表

字符 ASCII 码 功能描述
SOH 0x01 128 字节数据块起始标志
STX 0x02 1024 字节数据块起始标志
EOT 0x04 传输结束标志
ACK 0x06 确认接收成功
NAK 0x15 请求重传(校验失败/超时)
CAN 0x18 取消传输
‘C’ 0x43 接收方发起传输请求
字符 ASCII 码 功能描述
SOH 0x01 128 字节数据块起始标志
STX 0x02 1024 字节数据块起始标志
EOT 0x04 传输结束标志
ACK 0x06 确认接收成功
NAK 0x15 请求重传(校验失败/超时)
CAN 0x18 取消传输
‘C’ 0x43 接收方发起传输请求

1.4 传输流程

img

二、演示功能概述

本篇文章演示的内容为:使用Air780EHM核心板的UART1连接PC端的串口调试仿真工具SecureCRT,通过Ymodem协议接收文件传输。

三、准备硬件环境

参考:硬件环境清单第二章节内容,准备以及组装好硬件环境。

3.1 准备一块Air780EHM核心板:点击购买

img

3.2 连线对应表

Air780EPM开发板 USB 转 TTL 线
uart1_tx 白线
uart1_rx 绿线
gnd 黑线
Air780EPM开发板 USB 转 TTL 线
uart1_tx 白线
uart1_rx 绿线
gnd 黑线

3.3 硬件连接图

使用USB 转 TTL 线连接780EHM核心板的U1TX、U1RX和GND

img

四、准备软件环境

烧录工具:Luatools工具

Air780EHM烧录需要的固件和脚本文件:

内核固件文件(底层core固件文件):LuatOS-SoC_V2008_Air780EHM;内核固件:固件版本

脚本文件:https://gitee.com/openLuat/LuatOS/tree/master/module/Air780EHM/demo/ymodem

LuatOS运行所需要的lib文件:

使用Luatools烧录时,勾选 添加默认lib 选项,使用默认lib脚本文件

PC端工具SecureCRT:下载链接

五、代码API和代码解析

5.1 代码API

ymodem - 合宙模组资料中心

5.2 代码解析

1.定义一个ymodem_to函数,用于发送C字符,并重置ymodem处理程序

--  定义一个ymodem_to函数,用于发送C字符,并重置ymodem处理程序
local function ymodem_to() 
    while true do
        --  如果ymodem协议没有在运行,则发送请求;并重置ymodem处理程序
        if not ymodem_running then 
            uart.write(uartid, "C")
            ymodem.reset(ymodem_handler) 
        end
        sys.wait(500)
    end
end

2.定义一个ymodem_rx函数,用于接收数据

--  定义一个ymodem_rx函数,用于接收数据
local function ymodem_rx(id,len) 
    --  从uart接收数据到缓冲区
    uart.rx(id,rxbuff) 
    --  打印缓冲区已使用的大小
    log.info(rxbuff:used()) 
    --  调用ymodem.receive函数,接收数据
    local result,ack,flag,file_done,all_done = ymodem.receive(ymodem_handler,rxbuff) 
    ymodem_running = result
    log.info("result:",ymodem_running,ack,flag,file_done,all_done)
    rxbuff:del()
    if result then
        rxbuff:copy(0, ack,flag)
        uart.tx(id, rxbuff)
    end

    --  所有数据都接收完毕
    if all_done then 
        -- 判断/save.bin文件是否存在
        local exists=io.exists("/save.bin") 

        -- 判断/save.bin文件是否存在,存在则打印日志,显示/save.bin文件大小;不存在则打印日志,显示/save.bin文件不存在
        if exists then
            log.info("io", "save.bin file exists:", exists) 
            log.info("io", "save.bin file size:", io.fileSize("/save.bin")) 
        else
            log.info("io", "save.bin file not exists") 
        end

        --ymodem_running置为false,再次开始接收
        ymodem_running = false 
    end
    rxbuff:del()
end

六、运行结果展示

6.1完整代码

--[[
@module  main
@summary ymodem 接收文件应用功能模块 
@version 1.0
@date    2025.07.01
@author  杨鹏
@usage
本文件为Air780EHM核心板演示ymodem功能的代码示例,核心业务逻辑为:
1. 初始化串口通信
2. 创建Ymodem处理对象
    local ymodem_handler = ymodem.create("/","save.bin")
3. 启动请求发送任务
    uart.write(uartid, "C")
4. 监听串口数据接收
    uart.on(uartid, "receive", ymodem_rx)
5. 处理Ymodem数据包
    local function ymodem_rx(id,len)
]]

-- 根据实际设备选取不同的uartid
local uartid = 1 

--初始化
local result = uart.setup(
    uartid,--串口id
    115200,--波特率
    8,--数据位
    1--停止位
)
local taskName = "ymodem_to"

-- 处理未识别的消息
local function ymodem_to_cb(msg)
    log.info("ymodem_to_cb", msg[1], msg[2], msg[3], msg[4])
end

--  定义一个局部变量,用于表示Ymodem协议是否正在运行
local ymodem_running = false 

--  创建一个缓冲区,大小为1024 + 32
local rxbuff = zbuff.create(1024 + 32) 

--  创建一个ymodem处理程序,保存路径为"/",文件名为"save.bin"
local ymodem_handler = ymodem.create("/","save.bin")

--  定义一个ymodem_to函数,用于发送C字符,并重置ymodem处理程序
local function ymodem_to() 
    while true do
        --  如果ymodem协议没有在运行,则发送请求;并重置ymodem处理程序
        if not ymodem_running then 
            uart.write(uartid, "C")
            ymodem.reset(ymodem_handler) 
        end
        sys.wait(500)
    end
end

--  定义一个ymodem_rx函数,用于接收数据
local function ymodem_rx(id,len) 
    --  从uart接收数据到缓冲区
    uart.rx(id,rxbuff) 
    --  打印缓冲区已使用的大小
    log.info(rxbuff:used()) 
    --  调用ymodem.receive函数,接收数据
    local result,ack,flag,file_done,all_done = ymodem.receive(ymodem_handler,rxbuff) 
    ymodem_running = result
    log.info("result:",ymodem_running,ack,flag,file_done,all_done)
    rxbuff:del()
    if result then
        rxbuff:copy(0, ack,flag)
        uart.tx(id, rxbuff)
    end

    --  所有数据都接收完毕
    if all_done then 
        -- 判断/save.bin文件是否存在
        local exists=io.exists("/save.bin") 

        -- 判断/save.bin文件是否存在,存在则打印日志,显示/save.bin文件大小;不存在则打印日志,显示/save.bin文件不存在
        if exists then
            log.info("io", "save.bin file exists:", exists) 
            log.info("io", "save.bin file size:", io.fileSize("/save.bin")) 
        else
            log.info("io", "save.bin file not exists") 
        end

        --ymodem_running置为false,再次开始接收
        ymodem_running = false 
    end
    rxbuff:del()
end

--  监听串口接收事件
uart.on(uartid, "receive", ymodem_rx) 

--  监听串口发送事件
uart.on(uartid, "sent", function(id) 
    log.info("uart", "sent", id) 
end)

--创建并且启动一个task
--运行这个task的主函数ymodem_to
sysplus.taskInitEx(ymodem_to, taskName,ymodem_to_cb)

6.2 结果展示

6.2.1 SecureCRT使用指南:

img

img

6.2.2 1k文件数据传输:

发送端:传输完成

img

模组接收端:

img

6.2.3 10K文件数据传输:

发送端:传输完成

img

模组接收端:

img

七、总结

本文演示如何在Air780EHM核心板上面,通过UART1连接PC端的串口调试工具SecureCRT,进行Ymodem协议的文件传输测试。