ymodem - ymodem协议
作者:李源龙
一、概述
Ymodem协议是一种在串行通信(如串口)中使用的文件传输协议,它由Chuck Forsberg在Xmodem协议的基础上改进而来,核心特点是支持批量文件传输和每帧最多1024字节的数据块,相比前身Xmodem的128字节帧,传输效率显著提升。
该协议通过CRC-16循环冗余校验来检测传输错误,并利用ACK(确认)/NAK(否认)握手信号实现自动重传机制,从而保证数据传输的可靠性。
Ymodem协议在传输开始时会将文件名和文件大小作为元数据在起始帧中发送,使得接收方能够预先知晓文件信息,因此尤其适用于嵌入式系统中的固件升级(OTA)和Bootloader引导程序等场景
二、核心示例
1、核心示例是指:使用本库文件提供的核心API,开发的基础业务逻辑的演示代码;
2、核心示例的作用是:帮助开发者快速理解如何使用本库,所以核心示例的逻辑都比较简单;
3、更加完整和详细的demo,请参考 LuatOS仓库 中各个产品目录下的demo/ymodem
-- 根据实际设备选取不同的uartid
local uartid = 1
--初始化
local result = uart.setup(
uartid,--串口id
115200,--波特率
8,--数据位
1--停止位
)
local taskName = "ymodem_run"
-- 处理未识别的消息
local function ymodem_run_cb(msg)
log.info("ymodem_run_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_run函数,用于发送C字符,并重置ymodem处理程序
local function ymodem_run()
while true do
-- 如果ymodem协议没有在运行,则发送请求;并重置ymodem处理程序
if not ymodem_running then
--YMODEM 传输文件时,接收方会先发送一个字符 'C'来启动传输过程
uart.write(uartid, "C")
--发送完之后重置恢复到初始状态
ymodem.reset(ymodem_handler)
end
sys.wait(500)
end
end
-- 定义一个ymodem_rx函数,用于接收数据
local function ymodem_rx(id,len)
-- 从uart接收数据到缓冲区
while 1 do
log.info("uart", "缓冲区", uart.rxSize(id)) -- 缓冲区中的数据数量
local len = uart.rx(id, rxbuff)
if len <= 0 then
break
end
log.info("uart", "receive", id, rxbuff:used(), rxbuff:toStr())
end
-- 打印缓冲区已使用的大小
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()
--成功就发送ack和flag
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)
local function uart_sent_cb(id)
log.info("uart", "sent", id)
end
-- 监听串口发送事件
uart.on(uartid, "sent", uart_sent_cb)
--创建并且启动一个task
--运行这个task的主函数ymodem_run
sys.taskInit(ymodem_run, taskName,ymodem_run_cb)
三、常量详解
核心库常量,顾名思义是由合宙LuatOS内核固件中定义的、不可重新赋值或修改的固定值,在脚本代码中不需要声明,可直接调用;
ymodem核心库没有常量。
四、函数详解
ymodem.create(dir_path,file_path)
功能
创建一个ymodem处理句柄
注意事项
暂无
参数
dir_path
含义说明:保存的文件夹路径,默认是"/"路径;
数据类型:string;
取值范围:无特别限制;
是否必选:否;
注意事项:默认是"/"路径;
参数示例:ymodem.create("/")
file_path
含义说明:强制保存的文件名,默认是空,如果设置了,就会直接保存在该文件中;
数据类型:string;
取值范围:无特别限制;
是否必选:否;
注意事项:如果不填该参数,文件名默认对端发过来的文件名;
参数示例:ymodem.create("/","save.bin")
返回值
local ymodem_handler = ymodem.create("/","save.bin")
ymodem_handler
含义说明:ymodem创建成功返回的对象;
数据类型:userdata;
取值范围:无特别限制;
注意事项:无;
例子
local ymodem_handler = ymodem.create("/","save.bin")
ymodem.receive(handler, data)
功能
ymodem接收文件数据并保存
注意事项
暂无
参数
handler
含义说明:ymodem创建成功的对象;
数据类型:userdata;
取值范围:无特别限制;
是否必选:必须传入此参数;
注意事项:作为必需参数,若不提供会导致错误;
参数示例:local handler = ymodem.create("/","save.bin")
ymodem.receive(handler, data)
data
含义说明:串口接收的数据;
数据类型:string/zbuff;
取值范围:无特别限制;
是否必选:必须传入此参数;
注意事项:作为必需参数,若不提供会导致错误;
参数示例:local handler = ymodem.create("/","save.bin")
ymodem.receive(handler, data)
返回值
local result,ack,flag,file_done,all_done = ymodem.receive(handler, data)
result
含义说明:保存成功/失败;
数据类型:boolean;
取值范围:true/false;
注意事项:无;
ack
含义说明:ack值,需要通过串口/网络等途径返回发送方;
数据类型:number;
取值范围:0-255;
注意事项:无;
flag
含义说明:flag值,需要通过串口/网络等途径返回发送方,如果有ack值则不发送flag;
数据类型:number;
取值范围:0-255;
注意事项:无;
file_done
含义说明:文件是否接收完成;
数据类型:boolean;
取值范围:true/false 接收完成true,传输中false;
注意事项:无;
all_done
含义说明:整个传输是否完成;
数据类型:boolean;
取值范围:true/false 传输完成true,未完成false;
注意事项:无;
例子
-- 注意, 数据来源不限, 通常是uart.read得到data
local handler = ymodem.create("/","save.bin")
local result,ack,flag,file_done,all_done = ymodem.receive(handler, data)
ymodem.reset(handler)
功能
重置ymodem处理过程
注意事项
这个操作主要是把状态复位,之前传输过来的数据不会清空,下次传输不需要重新create。
参数 handler
含义说明:ymodem创建成功的对象;
数据类型:userdata;
取值范围:无特别限制;
是否必选:必须传入此参数;
注意事项:作为必需参数,若不提供会导致错误;
参数示例:local handler = ymodem.create("/","save.bin")
ymodem.reset(handler)
返回值
无
例子
-- 恢复到初始状态,一般用于接收出错后重置,从而进行下一次接收
local handler = ymodem.create("/","save.bin")
ymodem.reset(handler)
ymodem.release(handler)
功能
释放ymodem处理句柄
注意事项
暂无
参数 handler
含义说明:ymodem创建成功的对象;
数据类型:userdata;
取值范围:无特别限制;
是否必选:必须传入此参数;
注意事项:作为必需参数,若不提供会导致错误;
参数示例:local handler = ymodem.create("/","save.bin")
ymodem.release(handler)
返回值
无
例子
ymodem.release(handler)
五、函数详解
支持 LuatOS 开发的8000系列和780EHM、780EGH、780EHV的产品都支持 ymodem 核心库。