Browse Source

add:新增8000的xmodem的demo

liszt123 3 months ago
parent
commit
9600f3265d

+ 75 - 0
module/Air8000/demo/xmodem/main.lua

@@ -0,0 +1,75 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@version 1.0
+@date    2025.10.14
+@author  李源龙
+@usage
+本demo演示的核心功能为:
+用Air8000核心板利用xmodem协议,将模块内的文件从串口发送到对端
+主要提供了两种方式:
+1、文件存到脚本区里面,通过xmodem协议,把脚本区文件发给对端
+2、通过http下载文件到文件系统区,通过xmodem协议,把文件系统区文件发给对端
+
+更多说明参考本目录下的readme.md文件
+]]
+
+
+--[[
+必须定义PROJECT和VERSION变量,Luatools工具会用到这两个变量,远程升级功能也会用到这两个变量
+PROJECT:项目名,ascii string类型
+        可以随便定义,只要不使用,就行
+VERSION:项目版本号,ascii string类型
+        如果使用合宙iot.openluat.com进行远程升级,必须按照"XXX.YYY.ZZZ"三段格式定义:
+            X、Y、Z各表示1位数字,三个X表示的数字可以相同,也可以不同,同理三个Y和三个Z表示的数字也是可以相同,可以不同
+            因为历史原因,YYY这三位数字必须存在,但是没有任何用处,可以一直写为000
+        如果不使用合宙iot.openluat.com进行远程升级,根据自己项目的需求,自定义格式即可
+]]
+PROJECT = "xmodem_demo"
+VERSION = "001.000.000"
+
+
+-- 在日志中打印项目名和项目版本号
+log.info("main", PROJECT, VERSION)
+
+
+-- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
+-- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
+if wdt then
+    --配置喂狗超时时间为9秒钟
+    wdt.init(9000)
+    --启动一个循环定时器,每隔3秒钟喂一次狗
+    sys.timerLoopStart(wdt.feed, 3000)
+end
+
+
+-- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
+-- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
+-- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
+-- 启动errDump日志存储并且上传功能,600秒上传一次
+-- if errDump then
+--     errDump.config(true, 600)
+-- end
+
+
+-- 使用LuatOS开发的任何一个项目,都强烈建议使用远程升级FOTA功能
+-- 可以使用合宙的iot.openluat.com平台进行远程升级
+-- 也可以使用客户自己搭建的平台进行远程升级
+-- 远程升级的详细用法,可以参考fota的demo进行使用
+
+
+-- 启动一个循环定时器
+-- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
+-- 方便分析内存使用是否有异常
+-- sys.timerLoopStart(function()
+--     log.info("mem.lua", rtos.meminfo())
+--     log.info("mem.sys", rtos.meminfo("sys"))
+-- end, 3000)
+
+-- 加载网络环境检测看门狗功能模块
+require "xmodem_demo"
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行

+ 82 - 0
module/Air8000/demo/xmodem/readme.md

@@ -0,0 +1,82 @@
+
+## 演示功能概述
+本demo演示的核心功能为:
+使用Air8000核心板的UART1连接PC端的串口工具,通过xmodem协议接收文件。
+
+## 演示硬件环境
+
+1、Air8000核心板一块
+
+2、TYPE-C USB数据线一根
+
+3、USB转串口线数据线一根
+
+4、Air8000核心板和数据线的硬件接线方式为
+
+- Air8000核心板通过TYPE-C USB口供电;(核心板背面的功耗测试开关拨到OFF一端)
+
+- 如果测试发现软件频繁重启,重启原因值为:poweron reason 0,可能是供电不足,此时再通过直流稳压电源对核心板的vbat管脚进行4V供电,或者VIN管脚进行5V供电;
+
+- TYPE-C USB数据线直接插到核心板的TYPE-C USB座子,另外一端连接电脑USB口;
+
+- USB转串口数据线,一般来说,白线连接核心板的16/U1TX,绿线连接核心板的17/U1RX,黑线连接核心板的gnd,另外一端连接电脑USB口;
+
+| Air8000核心板 | USB转串口数据线 |
+| -------------- | -------------- |
+| U1TX           | 白线           |
+| U1RX           | 绿线           |
+| GND            | GND            |
+
+## 演示软件环境
+
+1、Luatools下载调试工具
+
+2、[Air8000最新版本固件](https://docs.openluat.com/air8000/luatos/firmware/)
+
+3、PC端的串口工具,例如SSCOM、LLCOM等都可以;
+
+
+## 演示核心步骤
+
+1、搭建好演示硬件环境
+
+2、不需要修改demo脚本代码
+
+3、Luatools烧录内核固件和demo脚本代码
+
+4、烧录成功后,自动开机运行
+
+5、打开串口工具,连接上Air8000 UATR1端口,Air8000等待接收到工具发送过来的字符'C',然后8000开始发送数据,工具端接收到数据返回0x06,0x06为xmodem协议的ack值表示正确接收,然后模块返回0x04,0x04为xmodem协议的​EOT​值,表示传输结束,然后对端发送0x06表示确认结束,Luatools的运行日志输出:
+
+发送脚本区的文件,日志内容如下:
+``` lua
+[2025-10-17 15:41:21.708][000000007.048] I/user.xmodem uart读取到数据: 430D0A 6
+[2025-10-17 15:41:21.754][000000007.050] I/user.xmodem 发送第 1 包
+[2025-10-17 15:41:21.762][000000007.107] D/mobile TIME_SYNC 0
+[2025-10-17 15:41:31.029][000000016.785] I/user.xmodem uart读取到数据: 06 2
+[2025-10-17 15:41:31.056][000000016.786] I/user.xmodem 文件到头了
+[2025-10-17 15:41:31.067][000000016.787] I/user.Xmodem start
+[2025-10-17 15:41:31.070][000000016.787] I/user.Xmodem send result true
+[2025-10-17 15:41:31.073][000000016.787] I/user.Xmodem send success
+
+```
+
+HTTP下载到文件系统区的,再通过xmodem协议发送日志如下:
+``` lua
+[2025-10-17 15:59:02.210][000000007.027] dns_run 676:airtest.openluat.com state 0 id 1 ipv6 0 use dns server2, try 0
+[2025-10-17 15:59:02.216][000000007.050] D/mobile TIME_SYNC 0
+[2025-10-17 15:59:02.231][000000007.070] dns_run 693:dns all done ,now stop
+[2025-10-17 15:59:02.249][000000007.183] I/user.http success 200
+[2025-10-17 15:59:02.261][000000007.183] I/user.HTTP receive ok 29
+[2025-10-17 15:59:02.270][000000007.187] I/user.文件读取 路径:/send.bin 内容:AA BB CC DD 01 02 03 04 05 06
+[2025-10-17 15:59:02.277][000000007.190] Uart_ChangeBR 1338:uart1, 115200 115203 26000000 3611
+[2025-10-17 15:59:03.762][000000008.800] I/user.xmodem uart读取到数据: 430D0A 6
+[2025-10-17 15:59:03.796][000000008.802] I/user.xmodem 发送第 1 包
+[2025-10-17 15:59:09.955][000000014.991] I/user.xmodem uart读取到数据: 06 2
+[2025-10-17 15:59:09.980][000000014.992] I/user.xmodem 文件到头了
+[2025-10-17 15:59:09.990][000000014.993] I/user.Xmodem start
+[2025-10-17 15:59:09.995][000000014.993] I/user.Xmodem send result true
+[2025-10-17 15:59:10.006][000000014.993] I/user.Xmodem send success
+
+
+```

+ 1 - 0
module/Air8000/demo/xmodem/send.bin

@@ -0,0 +1 @@
+AA BB CC DD 01 02 03 04 05 06

+ 93 - 0
module/Air8000/demo/xmodem/xmodem_demo.lua

@@ -0,0 +1,93 @@
+--[[
+@module  main
+@summary xmodem 发送文件应用功能模块 
+@version 1.0
+@date    2025.07.01
+@author  李源龙
+@usage
+本文件为Air8000核心板演示xmodem功能的代码示例,本文档主要提供了两种方案:
+1、把模块脚本区的文件利用xmodem协议通过uart发送到过去
+
+2、进行http下载文件,利用xmodem协议通过uart发送到过去
+]]
+
+--加载xmodem模块
+xmodem=require ("xmodem")
+
+--设置默认filepath为脚本区的send.bin文件
+local filepath="/luadb/send.bin"
+
+local taskName = "xmodem_run"
+
+
+local uart_id = 1    --串口号
+
+local baudrate = 115200  --波特率
+
+local file_path=filepath --文件路径
+
+local send_type=true  --true表示单次发送128字节,false表示单次发送1024字节
+
+local inform_data="wait C"    --发送前提示信息,告知对方要发送C字符来接收文件
+
+-- 处理未识别的消息
+local function xmodem_run_cb(msg)
+	log.info("xmodem_run_cb", msg[1], msg[2], msg[3], msg[4])
+end
+
+--http获取文件函数
+local  function http_recived_cb()
+    while not socket.adapter(socket.dft()) do
+        log.warn("httpplus_app_task_func", "wait IP_READY", socket.dft())
+        -- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
+        -- 或者等待1秒超时退出阻塞等待状态;
+        -- 注意:此处的1000毫秒超时不要修改的更长;
+        -- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
+        -- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
+        -- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
+        sys.waitUntil("IP_READY", 1000)
+    end
+    local path = "/send.bin"
+    -- 以下链接仅用于测试,禁止用于生产环境
+    local code, headers, body_size = http.request("GET", "http://airtest.openluat.com:2900/download/send.bin", nil, nil, {dst=path}).wait()
+    log.info("http", code==200 and "success" or "error", code)
+    if code==200 then
+       log.info("HTTP receive ok",body_size)
+       file = io.open(path, "rb")
+        if file then
+            content = file:read("*a")
+            log.info("文件读取", "路径:" .. path, "内容:" .. content)
+            file:close()
+        else
+            log.error("文件操作", "无法打开文件读取内容", "路径:" .. path)
+        end
+        file_path=path
+    end
+    
+end
+
+--  定义一个xmodem_run函数,用于用xmodem发送文件
+local function xmodem_run() 
+    --如果需要http下载文件,然后发送下载的文件,可以打开下面的http_recived_cb()函数
+    http_recived_cb()
+    
+    --启动xmodem发送
+    local result=xmodem.send(uart_id,baudrate,file_path,send_type)
+    --等待时间12秒,等待接收方发送C字符启动发送,发送结束后接收端发送ACK:0x06表示接收完成,文件全部传输完成之后模块发送EOT​:0x04表示传输结束,接收端返回0x06表示确认结束
+    log.info("Xmodem", "start")
+
+    log.info("Xmodem", "send result", result)
+    --判断是否传输成功,传输是否成功,都需要关闭xmodem
+    if result then
+        log.info("Xmodem", "send success")
+        xmodem.close(uart_id)
+    else
+        log.info("Xmodem", "send failed")
+        xmodem.close(uart_id)
+    end
+
+end
+
+--创建并且启动一个task
+--运行这个task的主函数xmodem_run
+sys.taskInit(xmodem_run, taskName,xmodem_run_cb)

+ 150 - 72
script/libs/xmodem.lua

@@ -1,19 +1,92 @@
 --[[
 @module xmodem
-@summary xmodem 驱动
+@summary xmodem 协议
 @version 1.0
-@date    2022.06.01
+@date    2025.10.17
 @author  Dozingfiretruck
 @usage
---注意:因使用了sys.wait()所有api需要在协程中使用
--- 用法实例
-local xmodem = require "xmodem"
-sys.taskInit(function()
-    xmodem.send(2,115200,"/luadb/test.bin")
-    while 1 do
-        sys.wait(1000)
+--加载xmodem模块
+xmodem=require ("xmodem")
+
+--设置默认filepath为脚本区的send.bin文件
+local filepath="/luadb/send.bin"
+
+local taskName = "xmodem_run"
+
+
+local uart_id = 1    --串口号
+
+local baudrate = 115200  --波特率
+
+local file_path=filepath --文件路径
+
+local send_type=true  --true表示单次发送128字节,false表示单次发送1024字节
+
+local inform_data="wait C"    --发送前提示信息,告知对方要发送C字符来接收文件
+
+-- 处理未识别的消息
+local function xmodem_run_cb(msg)
+	log.info("xmodem_run_cb", msg[1], msg[2], msg[3], msg[4])
+end
+
+--http获取文件函数
+local  function http_recived_cb()
+    while not socket.adapter(socket.dft()) do
+        log.warn("httpplus_app_task_func", "wait IP_READY", socket.dft())
+        -- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
+        -- 或者等待1秒超时退出阻塞等待状态;
+        -- 注意:此处的1000毫秒超时不要修改的更长;
+        -- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
+        -- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
+        -- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
+        sys.waitUntil("IP_READY", 1000)
+    end
+    local path = "/send.bin"
+    -- 以下链接仅用于测试,禁止用于生产环境
+    local code, headers, body_size = http.request("GET", "http://airtest.openluat.com:2900/download/send.bin", nil, nil, {dst=path}).wait()
+    log.info("http", code==200 and "success" or "error", code)
+    if code==200 then
+       log.info("HTTP receive ok",body_size)
+       file = io.open(path, "rb")
+        if file then
+            content = file:read("*a")
+            log.info("文件读取", "路径:" .. path, "内容:" .. content)
+            file:close()
+        else
+            log.error("文件操作", "无法打开文件读取内容", "路径:" .. path)
+        end
+        file_path=path
     end
-end)
+    
+end
+
+--  定义一个xmodem_run函数,用于用xmodem发送文件
+local function xmodem_run() 
+    --如果需要http下载文件,然后发送下载的文件,可以打开下面的http_recived_cb()函数
+    -- http_recived_cb()
+    
+    --启动xmodem发送
+    local result=xmodem.send(uart_id,baudrate,file_path,send_type,inform_data)
+    --等待时间12秒,等待接收方发送C字符启动发送,发送结束后接收端发送ACK:0x06表示接收完成,文件全部传输完成之后模块发送EOT​:0x04表示传输结束,接收端返回0x06表示确认结束
+    log.info("Xmodem", "start")
+
+    log.info("Xmodem", "send result", result)
+    --判断是否传输成功,传输是否成功,都需要关闭xmodem
+    if result then
+        log.info("Xmodem", "send success")
+        xmodem.close(uart_id)
+    else
+        log.info("Xmodem", "send failed")
+        xmodem.close(uart_id)
+    end
+
+end
+
+--创建并且启动一个task
+--运行这个task的主函数xmodem_run
+sys.taskInit(xmodem_run, taskName,xmodem_run_cb)
+
+
 ]]
 local xmodem = {}
 
@@ -35,6 +108,7 @@ local FRAME_ID_SIZE =   2
 local DATA_SIZE_SOH =   128
 local DATA_SIZE_STX =   1024
 
+
 local function uart_cb(id, len)
     local data = uart.read(id, 1024)
     if #data == 0 then
@@ -45,87 +119,91 @@ local function uart_cb(id, len)
     sys.publish("xmodem", data)
 end
 
+
 --[[
 xmodem 发送文件
-@api xmodem.send(uart_id, uart_br, file_path,type)
+@api xmodem.send(uart_id,baudrate,type,inform_data)
 @number uart_id uart端口号
 @number uart_br uart波特率
 @string file_path 文件路径
 @bool type 1k/128 默认1k
 @return bool 发送结果
 @usage
-xmodem.send(2,115200,"/luadb/test.bin")
+xmodem.send(1, 115200, "/luadb/send.bin",true)
 ]]
 
-function xmodem.send(uart_id, uart_br, file_path, type)
-    local ret, flen, cnt, crc
-
-    if type then
-        HEAD = SOH
-        DATA_SIZE = DATA_SIZE_SOH
-    else
-        HEAD = STX
-        DATA_SIZE = DATA_SIZE_STX
-    end
-    local XMODEM_SIZE = 1+FRAME_ID_SIZE+DATA_SIZE+CRC_SIZE
-    local packsn = 0
-    local xmodem_buff = zbuff.create(XMODEM_SIZE)
-    local data_buff = zbuff.create(DATA_SIZE)
-    local fd = io.open(file_path, "rb")
-    if fd then
-        uart.setup(uart_id,uart_br)
-        uart.on(uart_id, "receive", uart_cb)
-        local result, data = sys.waitUntil("xmodem", 12000)
-        if result and (data == CRC_CHR or data == NAK) then
-            cnt = 1
-            while true do
-                data_buff:set(0, CTRLZ)
-                ret, flen = fd:fill(data_buff,0,DATA_SIZE)
-                log.info("xmodem", "发送第", cnt, "包")
-                if flen > 0 then
-                    data_buff:seek(0)
-                    crc = crypto.crc16("XMODEM",data_buff)
-                    packsn = (packsn+1) & 0xff
-                    xmodem_buff[0] = 0x02
-                    xmodem_buff[1] = packsn
-                    xmodem_buff[2] = 0xff-xmodem_buff[1]
-                    data_buff:seek(DATA_SIZE)
-                    xmodem_buff:copy(3, data_buff)
-                    xmodem_buff[1027] = crc>>8
-                    xmodem_buff[1028] = crc&0xff
-                    xmodem_buff:seek(XMODEM_SIZE)
-                    -- log.info(xmodem_buff:used())
-                    :: RESEND ::
-                    uart.tx(uart_id, xmodem_buff)
-                    result, data = sys.waitUntil("xmodem", 10000)
-                    if result and data == ACK then
-                        cnt = cnt + 1
-                    elseif result and data == NAK then
-                        goto RESEND
+function xmodem.send(uart_id,baudrate,file_path,type,inform_data)
+        local ret, flen, cnt, crc
+        if type then
+            HEAD = SOH
+            DATA_SIZE = DATA_SIZE_SOH
+        else
+            HEAD = STX
+            DATA_SIZE = DATA_SIZE_STX
+        end
+        local XMODEM_SIZE = 1+FRAME_ID_SIZE+DATA_SIZE+CRC_SIZE
+        local packsn = 0
+        local xmodem_buff = zbuff.create(XMODEM_SIZE)
+        local data_buff = zbuff.create(DATA_SIZE)
+        local fd = io.open(file_path, "rb")
+        if fd then
+            uart.setup(uart_id,baudrate)
+            uart.on(uart_id, "receive", uart_cb)
+            if inform_data and  inform_data~="" then
+                uart.write(uart_id,inform_data)
+            end
+            local result, data = sys.waitUntil("xmodem", 12000)
+            if result and (data == CRC_CHR or data == NAK) then
+                cnt = 1
+                while true do
+                    data_buff:set(0, CTRLZ)
+                    ret, flen = fd:fill(data_buff,0,DATA_SIZE)
+                    log.info("xmodem", "发送第", cnt, "包")
+                    if flen > 0 then
+                        data_buff:seek(0)
+                        crc = crypto.crc16("XMODEM",data_buff)
+                        packsn = (packsn+1) & 0xff
+                        xmodem_buff[0] = 0x02
+                        xmodem_buff[1] = packsn
+                        xmodem_buff[2] = 0xff-xmodem_buff[1]
+                        data_buff:seek(DATA_SIZE)
+                        xmodem_buff:copy(3, data_buff)
+                        xmodem_buff[1027] = crc>>8
+                        xmodem_buff[1028] = crc&0xff
+                        xmodem_buff:seek(XMODEM_SIZE)
+                        -- log.info(xmodem_buff:used())
+                        :: RESEND ::
+                        uart.tx(uart_id, xmodem_buff)
+                        result, data = sys.waitUntil("xmodem", 10000)
+                        if result and data == ACK then
+                            cnt = cnt + 1
+                        elseif result and data == NAK then
+                            goto RESEND
+                        else
+                            uart.write(uart_id, string.char(EOT))
+                            log.info("xmodem", "发送失败")
+                            return false
+                        end
+                        if flen ~= DATA_SIZE then
+                            log.info("xmodem", "文件到头了")
+                            break
+                        end
                     else
-                        log.info("xmodem", "发送失败")
-                        return false
-                    end
-                    if flen ~= DATA_SIZE then
                         log.info("xmodem", "文件到头了")
                         break
                     end
-                else
-                    log.info("xmodem", "文件到头了")
-                    break
                 end
+                uart.write(uart_id, string.char(EOT))
+                fd:close()
+                return true
+            else
+                log.info("xmodem", "不支持的起始数据包",data)
+                return false
             end
-            uart.write(uart_id, string.char(EOT))
-            fd:close()
-            return true
         else
-            log.info("xmodem", "不支持的起始数据包",data)
+            log.info("xmodem", "待传输的文件不存在")
             return false
         end
-    else
-        log.info("xmodem", "待传输的文件不存在")
-        return false
-    end
 end
 
 --[[