Browse Source

ADD:增加各个型号下的fs_iodemo

wangpenglin 4 months ago
parent
commit
ea7de31ac9

+ 282 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/fs_io/flash_fs_io.lua

@@ -0,0 +1,282 @@
+--[[
+@module  flash_fs_io
+@summary 内置Flash文件系统操作测试模块
+@version 1.0.0
+@date    2025.09.23
+@author  王棚嶙
+@usage
+本文件为内置Flash文件系统的操作测试流程:
+1. 获取文件系统信息( io.fsstat)
+2. 创建目录
+3. 创建并写入文件
+4. 检查文件是否存在
+5. 获取文件大小(io.fileSize)
+6. 读取文件内容
+7. 启动计数文件操作
+8. 文件追加测试
+9. 按行读取测试
+10. 文件重命名
+11. 列举目录内容
+12. 删除文件
+13. 删除目录
+本文件没有对外接口,直接在main.lua中require "flash_fs_io"就可以加载运行
+]]
+
+function flash_fs_io_task()
+    -- 使用内置Flash文件系统,根目录为"/",
+    local base_path = "/"
+    -- 创建一个目录
+    local demo_dir = "flash_demo"
+    -- 文件名
+    local dir_path = base_path .. demo_dir
+
+    -- ########## 开始进行内置Flash文件系统操作 ##########
+    log.info("文件系统操作", "===== 开始文件系统操作 =====")
+
+    -- 1. 获取文件系统信息 (使用 io.fsstat接口)
+    local success, total_blocks, used_blocks, block_size, fs_type  =  io.fsstat(base_path)
+    if success then
+        log.info(" io.fsstat成功:", 
+            "总空间=" .. total_blocks .. "块", 
+            "已用=" .. used_blocks .. "块", 
+            "块大小=" .. block_size.."字节",
+            "类型=" .. fs_type)
+    else
+        log.error(" io.fsstat", "获取文件系统信息失败")
+        return
+    end
+
+    -- 2. 创建目录
+    -- 如果目录不存在,则创建目录
+    if not io.dexist(dir_path) then
+        -- 创建目录
+        if io.mkdir(dir_path) then
+            log.info("io.mkdir", "目录创建成功", "路径:" .. dir_path)
+        else
+            log.error("io.mkdir", "目录创建失败", "路径:" .. dir_path)
+            return
+        end
+    else
+        log.warn("io.mkdir", "目录已存在,跳过创建", "路径:" .. dir_path)
+    end
+
+    -- 3. 创建并写入文件
+    local file_path = dir_path .. "/boottime"
+    local file = io.open(file_path, "wb")
+    if file then
+        file:write("这是内置Flash文件系统API文档示例的测试内容")
+        file:close()
+        log.info("文件创建", "文件写入成功", "路径:" .. file_path)
+    else
+        log.error("文件创建", "文件创建失败", "路径:" .. file_path)
+        return
+    end
+
+    -- 4. 检查文件是否存在
+    if io.exists(file_path) then
+        log.info("io.exists", "文件存在", "路径:" .. file_path)
+    else
+        log.error("io.exists", "文件不存在", "路径:" .. file_path)
+        return
+    end
+
+    -- 5. 获取文件大小 (使用io.fileSize接口)
+    local file_size = io.fileSize(file_path)
+    if file_size then
+        log.info("io.fileSize", "文件大小:" .. file_size .. "字节", "路径:" .. file_path)
+    else
+        log.error("io.fileSize", "获取文件大小失败", "路径:" .. file_path)
+        return
+    end
+
+    -- 6. 读取文件内容
+    file = io.open(file_path, "rb")
+    if file then
+        local content = file:read("*a")
+        log.info("文件读取", "路径:" .. file_path, "内容:" .. content)
+        file:close()
+    else
+        log.error("文件操作", "无法打开文件读取内容", "路径:" .. file_path)
+        return
+    end
+
+    -- 7. 启动计数文件操作
+    local count = 0
+    file = io.open(file_path, "rb")
+    if file then
+        local data = file:read("*a")
+        log.info("启动计数", "文件内容:", data, "十六进制:", data:toHex())
+        count = tonumber(data) or 0
+        file:close()
+    else
+        log.warn("启动计数", "文件不存在或无法打开")
+    end
+
+    log.info("启动计数", "当前值:", count)
+    count = count + 1
+    log.info("启动计数", "更新值:", count)
+
+    file = io.open(file_path, "wb")
+    if file then
+        file:write(tostring(count))
+        file:close()
+        log.info("文件写入", "路径:" .. file_path, "内容:", count)
+    else
+        log.error("文件写入", "无法打开文件", "路径:" .. file_path)
+        return
+    end
+
+    -- 8. 文件追加测试
+    local append_file = dir_path .. "/test_a"
+    os.remove(append_file) -- 清理旧文件
+
+    file = io.open(append_file, "wb")
+    if file then
+        file:write("ABC")
+        file:close()
+        log.info("文件创建", "路径:" .. append_file, "初始内容:ABC")
+    else
+        log.error("文件创建", "无法创建文件", "路径:" .. append_file)
+        return
+    end
+
+    file = io.open(append_file, "a+")
+    if file then
+        file:write("def")
+        file:close()
+        log.info("文件追加", "路径:" .. append_file, "追加内容:def")
+    else
+        log.error("文件追加", "无法打开文件进行追加", "路径:" .. append_file)
+        return
+    end
+
+    -- 验证追加结果
+    file = io.open(append_file, "r")
+    if file then
+        local data = file:read("*a")
+        log.info("文件验证", "路径:" .. append_file, "内容:" .. data, "结果:",
+            data == "ABCdef" and "成功" or "失败")
+        file:close()
+    else
+        log.error("文件验证", "无法打开文件进行验证", "路径:" .. append_file)
+        return
+    end
+
+    -- 9. 按行读取测试
+    local line_file = dir_path .. "/testline"
+    file = io.open(line_file, "w")
+    if file then
+        file:write("abc\n")
+        file:write("123\n")
+        file:write("wendal\n")
+        file:close()
+        log.info("文件创建", "路径:" .. line_file, "写入3行文本")
+    else
+        log.error("文件创建", "无法创建文件", "路径:" .. line_file)
+        return
+    end
+
+    file = io.open(line_file, "r")
+    if file then
+        log.info("按行读取", "路径:" .. line_file, "第1行:", file:read("*l"))
+        log.info("按行读取", "路径:" .. line_file, "第2行:", file:read("*l"))
+        log.info("按行读取", "路径:" .. line_file, "第3行:", file:read("*l"))
+        file:close()
+    else
+        log.error("按行读取", "无法打开文件", "路径:" .. line_file)
+        return
+    end
+
+    -- 10. 文件重命名
+    local old_path = append_file
+    local new_path = dir_path .. "/renamed_file.txt"
+    local success, err = os.rename(old_path, new_path)
+    if success then
+        log.info("os.rename", "文件重命名成功", "原路径:" .. old_path, "新路径:" .. new_path)
+
+        -- 验证重命名结果
+        if io.exists(new_path) and not io.exists(old_path) then
+            log.info("验证结果", "重命名验证成功", "新文件存在", "原文件不存在")
+        else
+            log.error("验证结果", "重命名验证失败")
+        end
+    else
+        log.error("os.rename", "重命名失败", "错误:" .. tostring(err), "原路径:" .. old_path)
+        return
+    end
+
+    -- 11. 列举目录内容
+    log.info("目录操作", "===== 开始目录列举 =====")
+
+    local ret, data = io.lsdir(dir_path, 50, 0)
+    if ret then
+        log.info("fs", "lsdir", json.encode(data))
+    else
+        log.info("fs", "lsdir", "fail", ret, data)
+        return
+    end
+
+    -- 12. 删除文件测试
+    if os.remove(new_path) then
+        log.info("os.remove", "文件删除成功", "路径:" .. new_path)
+        if not io.exists(new_path) then
+            log.info("验证结果", "renamed_file.txt文件删除验证成功")
+        else
+            log.error("验证结果", "renamed_file.txt文件删除验证失败")
+        end
+    else
+        log.error("os.remove", "renamed_file.txt文件删除失败", "路径:" .. new_path)
+        return
+    end
+
+    if os.remove(line_file) then
+        log.info("os.remove", "testline文件删除成功", "路径:" .. line_file)
+        if not io.exists(line_file) then
+            log.info("验证结果", "testline文件删除验证成功")
+        else
+            log.error("验证结果", "testline文件删除验证失败")
+        end
+    else
+        log.error("os.remove", "testline文件删除失败", "路径:" .. line_file)
+        return
+    end
+
+    if os.remove(file_path) then
+        log.info("os.remove", "文件删除成功", "路径:" .. file_path)
+        if not io.exists(file_path) then
+            log.info("验证结果", "boottime文件删除验证成功")
+        else
+            log.error("验证结果", "boottime文件删除验证失败")
+        end
+    else
+        log.error("os.remove", "boottime文件删除失败", "路径:" .. file_path)
+        return
+    end
+
+    -- 13. 删除目录
+    if io.rmdir(dir_path) then
+        log.info("io.rmdir", "目录删除成功", "路径:" .. dir_path)
+        if not io.dexist(dir_path) then
+            log.info("验证结果", "目录删除验证成功")
+        else
+            log.error("验证结果", "目录删除验证失败")
+        end
+    else
+        log.error("io.rmdir", "目录删除失败", "路径:" .. dir_path)
+        return
+    end
+
+    -- 再次获取文件系统信息,查看空间变化
+    local final_success, final_total_blocks, final_used_blocks, final_block_size, final_fs_type =  io.fsstat(base_path)
+    if final_success then
+        log.info(" io.fsstat", "操作后文件系统信息:", 
+                 "总空间=" .. final_total_blocks .. "块", 
+                 "已用=" .. final_used_blocks .. "块", 
+                 "块大小=" .. final_block_size.."字节",
+                 "类型=" .. final_fs_type)
+    end
+
+    log.info("文件系统操作", "===== 文件系统操作完成 =====")
+end
+
+sys.taskInit(flash_fs_io_task)

+ 74 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/fs_io/http_download_flash.lua

@@ -0,0 +1,74 @@
+--[[
+@module http_download_flash
+@summary HTTP下载文件到内置Flash模块
+@version 1.0.0
+@date    2025.09.23
+@author  王棚嶙
+@usage
+本文件演示的功能为通过HTTP下载文件到内置Flash中:
+1. 网络就绪检测
+2. 创建HTTP下载任务并等待完成
+3. 记录下载结果
+4. 获取并记录文件大小(使用io.fileSize)
+本文件没有对外接口,直接在main.lua中require "http_download_flash"即可
+]]
+
+local function http_download_flash_task()
+    -- 阶段1: 网络就绪检测
+    while not socket.adapter(socket.dft()) do
+        log.warn("HTTP下载", "等待网络连接", socket.dft())
+        sys.waitUntil("IP_READY", 1000)
+    end
+
+    log.info("HTTP下载", "网络已就绪", socket.dft())
+
+    -- 阶段2: 执行下载任务
+    log.info("HTTP下载", "开始下载任务")
+
+    -- 创建下载目录
+    local download_dir = "/downloads"
+    if not io.dexist(download_dir) then
+        io.mkdir(download_dir)
+    end
+
+    -- 核心下载操作开始
+    local code, headers, body_size = http.request("GET",
+                                    "https://gitee.com/openLuat/LuatOS/raw/master/module/Air780EHM_Air780EHV_Air780EGH/demo/audio/sample-6s.mp3",
+                                    nil, nil, {dst = download_dir .. "/sample-6s.mp3"}).wait()
+
+    -- 阶段3: 记录下载结果
+    log.info("HTTP下载", "下载完成", 
+        code == 200 and "success" or "error", 
+        code, 
+        json.encode(headers or {}), 
+        body_size) 
+        
+    if code == 200 then
+        -- 获取实际文件大小 (使用io.fileSize接口)
+        local actual_size = io.fileSize(download_dir .. "/sample-6s.mp3")
+        if not actual_size then
+            -- 备用方案
+            actual_size = io.fileSize(download_dir .. "/sample-6s.mp3")
+        end
+        
+        log.info("HTTP下载", "文件大小验证", "预期:", body_size, "实际:", actual_size)
+        
+        if actual_size ~= body_size then
+            log.error("HTTP下载", "文件大小不一致", "预期:", body_size, "实际:", actual_size)
+        end
+        
+        -- 展示下载后的文件系统状态
+        local success, total_blocks, used_blocks, block_size, fs_type =  io.fsstat("/")
+        if success then
+            log.info("HTTP下载", "下载后文件系统信息:", 
+                     "总空间=" .. total_blocks .. "块", 
+                     "已用=" .. used_blocks .. "块", 
+                     "块大小=" .. block_size.."字节",
+                     "类型=" .. fs_type)
+        end
+    end
+
+end
+
+-- 创建下载任务
+sys.taskInit(http_download_flash_task)

+ 78 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/fs_io/main.lua

@@ -0,0 +1,78 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@version 001.000.000
+@date    2025.09.23
+@author  王棚嶙
+@usage
+本 Demo 演示了在Air780EHM/780EGH/780EHV内置Flash文件系统中的完整操作流程:
+1. 基础操作:看门狗守护机制
+2. 文件系统操作:
+   - 文件系统信息查询( io.fsstat)
+   - 文件大小获取(io.fileSize)
+   - 文件创建/读写/追加
+   - 目录创建/删除
+   - 文件重命名/删除
+   - 文件存在性检查
+3. 下载功能:
+   - 网络检测与HTTP文件下载到内置Flash
+]]
+
+--[[
+必须定义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 = "flash_fs_io_demo"
+VERSION = "001.000.000"
+
+-- 在日志中打印项目名和项目版本号
+log.info("main", PROJECT, VERSION)
+
+-- 添加硬狗防止程序卡死
+if wdt then
+    -- 初始化watchdog设置为9s
+    wdt.init(9000)
+    -- 3s喂一次狗 
+    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)
+
+--[[在加载以下两个功能时,建议分别打开进行测试,因为文件操作和http下载功能是异步操作。放到一个项目中,如果加载的时间点是随机的,就会出现哪个任务先抢到CPU时间片,哪个就先执行,不符合正常的业务逻辑,用户在参考编程的时候也要注意。]]
+
+-- 加载内置Flash文件系统操作演示模块
+require "flash_fs_io"
+-- 加载HTTP下载存入内置Flash功能演示模块
+-- require "http_download_flash"
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+-- sys.run()之后后面不要加任何语句!!!!!
+sys.run()

+ 143 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/fs_io/readme.md

@@ -0,0 +1,143 @@
+## **功能模块介绍**
+
+本 Demo 演示了在Air780EHM/780EGH/780EHV内置Flash文件系统中的完整操作流程,覆盖了从文件系统读写到高级文件操作的完整功能链。项目分为两个核心模块:
+
+1、main.lua:主程序入口 <br> 
+2、flash_fs_io.lua:内置Flash文件系统的操作测试流程模块,实现文件系统管理、文件操作和目录管理功能。<br> 
+3、http_download_flash.lua:HTTP下载模块,演示HTTP下载文件到内置Flash中的功能
+
+## **演示功能概述**
+
+### 1、主程序入口模块(main.lua)
+
+- 初始化项目信息和版本号
+- 初始化看门狗,并定时喂狗
+- 启动一个循环定时器,每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况方便分析内存使用是否有异常
+- 加载flash_fs_io模块(通过require "flash_fs_io")
+- 加载http_download_flash模块(通过require "http_download_flash")
+- 最后运行sys.run()。
+
+### 2、内置Flash文件系统演示模块(flash_fs_io.lua)
+
+#### 文件操作
+- 获取文件系统信息( io.fsstat)
+- 创建目录:io.mkdir("/flash_demo")
+- 创建/写入文件: io.open("/flash_demo/boottime", "wb")
+- 检查文件存在: io.exists(file_path)
+- 获取文件大小:io.fileSize(file_path)
+- 读取文件内容: io.open(file_path, "rb"):read("*a")
+- 启动计数文件: 记录设备启动次数
+- 文件追加: io.open(append_file, "a+")
+- 按行读取: file:read("*l")
+- 文件关闭: file:close()
+- 文件重命名: os.rename(old_path, new_path)
+- 列举目录: io.lsdir(dir_path)
+- 删除文件: os.remove(file_path)
+- 删除目录: io.rmdir(dir_path)
+
+### 3、HTTP下载功能 (http_download_flash.lua)
+
+
+#### 网络就绪检测
+
+- 1秒循环等待IP就绪
+- 网络故障处理机制
+
+#### 安全下载
+
+- HTTP下载
+
+#### 结果处理
+
+- 下载状态码解析
+- 自动文件大小验证
+- 获取文件系统信息(fs.fsstat)
+
+## **演示硬件环境**
+
+1、Air780EHM核心板一块(Air780EHM/780EGH/780EHV三种模块的核心板接线方式相同,这里以Air780EHM为例)
+
+2、TYPE-C USB数据线一根
+
+3、SIM卡一张
+
+4、Air780EHM/780EGH/780EHV核心板和数据线的硬件接线方式为
+
+- Air780EHM核心板通过TYPE-C USB口供电;(核心板USB旁边的开关拨到on一端)
+
+- TYPE-C USB数据线直接插到核心板的TYPE-C USB座子,另外一端连接电脑USB口;
+
+## **演示软件环境**
+
+1、Luatools下载调试工具: https://docs.openluat.com/air780epm/common/Luatools/
+
+2、内核固件版本:
+Air780EHM:https://docs.openluat.com/air780epm/luatos/firmware/version/
+Air780EGH:https://docs.openluat.com/air780egh/luatos/firmware/version/
+Air780EHV:https://docs.openluat.com/air780ehv/luatos/firmware/version/
+
+## **演示核心步骤**
+
+1、搭建好硬件环境
+
+2、通过Luatools将demo与固件烧录到开发板中
+
+3、烧录好后,板子开机将会在Luatools上看到如下打印
+
+```lua
+
+(1)文件操作演示
+[2025-10-22 15:23:25.096][000000000.595] I/user.文件系统操作 ===== 开始文件系统操作 =====
+[2025-10-22 15:23:25.104][000000000.601] I/user. io.fsstat成功: 总空间=192块 已用=20块 块大小=4096字节 类型=lfs
+[2025-10-22 15:23:25.118][000000000.644] I/user.io.mkdir 目录创建成功 路径:/flash_demo
+[2025-10-22 15:23:25.127][000000000.648] I/user.文件创建 文件写入成功 路径:/flash_demo/boottime
+[2025-10-22 15:23:25.145][000000000.651] I/user.io.exists 文件存在 路径:/flash_demo/boottime
+[2025-10-22 15:23:25.157][000000000.654] I/user.io.fileSize 文件大小:59字节 路径:/flash_demo/boottime
+[2025-10-22 15:23:25.165][000000000.657] I/user.文件读取 路径:/flash_demo/boottime 内容:这是内置Flash文件系统API文档示例的测试内容
+[2025-10-22 15:23:25.181][000000000.660] I/user.启动计数 文件内容: 这是内置Flash文件系统API文档示例的测试内容 十六进制: E8BF99E698AFE58685E7BDAE466C617368E69687E4BBB6E7B3BBE7BB9F415049E69687E6A1A3E7A4BAE4BE8BE79A84E6B58BE8AF95E58685E5AEB9 118
+[2025-10-22 15:23:25.189][000000000.660] I/user.启动计数 当前值: 0
+[2025-10-22 15:23:25.211][000000000.660] I/user.启动计数 更新值: 1
+[2025-10-22 15:23:25.217][000000000.663] I/user.文件写入 路径:/flash_demo/boottime 内容: 1
+[2025-10-22 15:23:25.224][000000000.669] I/user.文件创建 路径:/flash_demo/test_a 初始内容:ABC
+[2025-10-22 15:23:25.245][000000000.672] I/user.文件追加 路径:/flash_demo/test_a 追加内容:def
+[2025-10-22 15:23:25.251][000000000.675] I/user.文件验证 路径:/flash_demo/test_a 内容:ABCdef 结果: 成功
+[2025-10-22 15:23:25.267][000000000.678] I/user.文件创建 路径:/flash_demo/testline 写入3行文本
+[2025-10-22 15:23:25.277][000000000.681] I/user.按行读取 路径:/flash_demo/testline 第1行: abc
+[2025-10-22 15:23:25.285][000000000.682] I/user.按行读取 路径:/flash_demo/testline 第2行: 123
+[2025-10-22 15:23:25.295][000000000.682] I/user.按行读取 路径:/flash_demo/testline 第3行: wendal
+[2025-10-22 15:23:25.301][000000000.689] I/user.os.rename 文件重命名成功 原路径:/flash_demo/test_a 新路径:/flash_demo/renamed_file.txt
+[2025-10-22 15:23:25.312][000000000.694] D/vfs fopen /flash_demo/test_a r not found
+[2025-10-22 15:23:25.321][000000000.694] I/user.验证结果 重命名验证成功 新文件存在 原文件不存在
+[2025-10-22 15:23:25.340][000000000.695] I/user.目录操作 ===== 开始目录列举 =====
+[2025-10-22 15:23:25.348][000000000.706] I/user.fs lsdir [{"name":"boottime","size":1,"type":0},{"name":"renamed_file.txt","size":6,"type":0},{"name":"testline","size":15,"type":0}]
+[2025-10-22 15:23:25.359][000000000.710] I/user.os.remove 文件删除成功 路径:/flash_demo/renamed_file.txt
+[2025-10-22 15:23:25.366][000000000.713] D/vfs fopen /flash_demo/renamed_file.txt r not found
+[2025-10-22 15:23:25.373][000000000.713] I/user.验证结果 renamed_file.txt文件删除验证成功
+[2025-10-22 15:23:25.378][000000000.716] I/user.os.remove testline文件删除成功 路径:/flash_demo/testline
+[2025-10-22 15:23:25.390][000000000.719] D/vfs fopen /flash_demo/testline r not found
+[2025-10-22 15:23:25.395][000000000.719] I/user.验证结果 testline文件删除验证成功
+[2025-10-22 15:23:25.415][000000000.723] I/user.os.remove 文件删除成功 路径:/flash_demo/boottime
+[2025-10-22 15:23:25.423][000000000.726] D/vfs fopen /flash_demo/boottime r not found
+[2025-10-22 15:23:25.444][000000000.726] I/user.验证结果 boottime文件删除验证成功
+[2025-10-22 15:23:25.453][000000000.732] I/user.io.rmdir 目录删除成功 路径:/flash_demo
+[2025-10-22 15:23:25.464][000000000.734] I/user.验证结果 目录删除验证成功
+[2025-10-22 15:23:25.477][000000000.740] I/user. io.fsstat 操作后文件系统信息: 总空间=192块 已用=20块 块大小=4096字节 类型=lfs
+[2025-10-22 15:23:25.484][000000000.740] I/user.文件系统操作 ===== 文件系统操作完成 =====
+
+
+
+
+(2)网络连接与HTTP下载
+[2025-10-22 15:34:04.507][000000007.471] I/user.HTTP下载 网络已就绪 1 3
+[2025-10-22 15:34:04.550][000000007.471] I/user.HTTP下载 开始下载任务
+[2025-10-22 15:34:04.579][000000007.478] dns_run 676:gitee.com state 0 id 1 ipv6 0 use dns server2, try 0
+[2025-10-22 15:34:04.604][000000007.508] D/mobile TIME_SYNC 0
+[2025-10-22 15:34:04.734][000000007.517] dns_run 693:dns all done ,now stop
+[2025-10-22 15:34:06.390][000000009.741] I/user.HTTP下载 下载完成 success 200 
+[2025-10-22 15:34:06.422][000000009.741] {"Age":"0","Cache-Control":"public, max-age=60","Via":"1.1 varnish","Transfer-Encoding":"chunked","Date":"Wed, 22 Oct 2025 07:34:04 GMT","Access-Control-Allow-Credentials":"true","Vary":"Accept-Encoding","X-Served-By":"cache-ffe9","X-Gitee-Server":"http-pilot 1.9.21","Connection":"keep-alive","Server":"ADAS\/1.0.214","Access-Control-Allow-Headers":"Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With,X-CustomHeader,Content-Range,Range,Set-Language","Content-Security-Policy":"default-src 'none'; style-src 'unsafe-inline'; sandbox","X-Request-Id":"fa536af1-51bd-400f-8d4b-7322355a9db2","Accept-Ranges":"bytes","Etag":"W\/\"2aaa2788d394a924e258d6f26ad78b8c948950f5\"","Content-Type":"text\/plain; charset=utf-8","Access-Control-Allow-Methods":"GET, POST, PUT, PATCH, DELETE, OPTIONS","X-Frame-Options":"DENY","X-Cache":"MISS","Set-Cookie":"BEC=1f1759df3ccd099821dcf0da6feb0357;Path=\/;Max-Age=126000"}
+[2025-10-22 15:34:06.477][000000009.742]  103070
+[2025-10-22 15:34:06.492][000000009.745] I/user.HTTP下载 文件大小验证 预期: 103070 实际: 103070
+[2025-10-22 15:34:06.525][000000009.751] I/user.HTTP下载 下载后文件系统信息: 总空间=192块 已用=46块 块大小=4096字节 类型=lfs
+
+
+```

+ 282 - 0
module/Air780EPM/demo/fs_io/flash_fs_io.lua

@@ -0,0 +1,282 @@
+--[[
+@module  flash_fs_io
+@summary 内置Flash文件系统操作测试模块
+@version 1.0.0
+@date    2025.09.23
+@author  王棚嶙
+@usage
+本文件为内置Flash文件系统的操作测试流程:
+1. 获取文件系统信息( io.fsstat)
+2. 创建目录
+3. 创建并写入文件
+4. 检查文件是否存在
+5. 获取文件大小(io.fileSize)
+6. 读取文件内容
+7. 启动计数文件操作
+8. 文件追加测试
+9. 按行读取测试
+10. 文件重命名
+11. 列举目录内容
+12. 删除文件
+13. 删除目录
+本文件没有对外接口,直接在main.lua中require "flash_fs_io"就可以加载运行
+]]
+
+function flash_fs_io_task()
+    -- 使用内置Flash文件系统,根目录为"/",
+    local base_path = "/"
+    -- 创建一个目录
+    local demo_dir = "flash_demo"
+    -- 文件名
+    local dir_path = base_path .. demo_dir
+
+    -- ########## 开始进行内置Flash文件系统操作 ##########
+    log.info("文件系统操作", "===== 开始文件系统操作 =====")
+
+    -- 1. 获取文件系统信息 (使用 io.fsstat接口)
+    local success, total_blocks, used_blocks, block_size, fs_type  =  io.fsstat(base_path)
+    if success then
+        log.info(" io.fsstat成功:", 
+            "总空间=" .. total_blocks .. "块", 
+            "已用=" .. used_blocks .. "块", 
+            "块大小=" .. block_size.."字节",
+            "类型=" .. fs_type)
+    else
+        log.error(" io.fsstat", "获取文件系统信息失败")
+        return
+    end
+
+    -- 2. 创建目录
+    -- 如果目录不存在,则创建目录
+    if not io.dexist(dir_path) then
+        -- 创建目录
+        if io.mkdir(dir_path) then
+            log.info("io.mkdir", "目录创建成功", "路径:" .. dir_path)
+        else
+            log.error("io.mkdir", "目录创建失败", "路径:" .. dir_path)
+            return
+        end
+    else
+        log.warn("io.mkdir", "目录已存在,跳过创建", "路径:" .. dir_path)
+    end
+
+    -- 3. 创建并写入文件
+    local file_path = dir_path .. "/boottime"
+    local file = io.open(file_path, "wb")
+    if file then
+        file:write("这是内置Flash文件系统API文档示例的测试内容")
+        file:close()
+        log.info("文件创建", "文件写入成功", "路径:" .. file_path)
+    else
+        log.error("文件创建", "文件创建失败", "路径:" .. file_path)
+        return
+    end
+
+    -- 4. 检查文件是否存在
+    if io.exists(file_path) then
+        log.info("io.exists", "文件存在", "路径:" .. file_path)
+    else
+        log.error("io.exists", "文件不存在", "路径:" .. file_path)
+        return
+    end
+
+    -- 5. 获取文件大小 (使用io.fileSize接口)
+    local file_size = io.fileSize(file_path)
+    if file_size then
+        log.info("io.fileSize", "文件大小:" .. file_size .. "字节", "路径:" .. file_path)
+    else
+        log.error("io.fileSize", "获取文件大小失败", "路径:" .. file_path)
+        return
+    end
+
+    -- 6. 读取文件内容
+    file = io.open(file_path, "rb")
+    if file then
+        local content = file:read("*a")
+        log.info("文件读取", "路径:" .. file_path, "内容:" .. content)
+        file:close()
+    else
+        log.error("文件操作", "无法打开文件读取内容", "路径:" .. file_path)
+        return
+    end
+
+    -- 7. 启动计数文件操作
+    local count = 0
+    file = io.open(file_path, "rb")
+    if file then
+        local data = file:read("*a")
+        log.info("启动计数", "文件内容:", data, "十六进制:", data:toHex())
+        count = tonumber(data) or 0
+        file:close()
+    else
+        log.warn("启动计数", "文件不存在或无法打开")
+    end
+
+    log.info("启动计数", "当前值:", count)
+    count = count + 1
+    log.info("启动计数", "更新值:", count)
+
+    file = io.open(file_path, "wb")
+    if file then
+        file:write(tostring(count))
+        file:close()
+        log.info("文件写入", "路径:" .. file_path, "内容:", count)
+    else
+        log.error("文件写入", "无法打开文件", "路径:" .. file_path)
+        return
+    end
+
+    -- 8. 文件追加测试
+    local append_file = dir_path .. "/test_a"
+    os.remove(append_file) -- 清理旧文件
+
+    file = io.open(append_file, "wb")
+    if file then
+        file:write("ABC")
+        file:close()
+        log.info("文件创建", "路径:" .. append_file, "初始内容:ABC")
+    else
+        log.error("文件创建", "无法创建文件", "路径:" .. append_file)
+        return
+    end
+
+    file = io.open(append_file, "a+")
+    if file then
+        file:write("def")
+        file:close()
+        log.info("文件追加", "路径:" .. append_file, "追加内容:def")
+    else
+        log.error("文件追加", "无法打开文件进行追加", "路径:" .. append_file)
+        return
+    end
+
+    -- 验证追加结果
+    file = io.open(append_file, "r")
+    if file then
+        local data = file:read("*a")
+        log.info("文件验证", "路径:" .. append_file, "内容:" .. data, "结果:",
+            data == "ABCdef" and "成功" or "失败")
+        file:close()
+    else
+        log.error("文件验证", "无法打开文件进行验证", "路径:" .. append_file)
+        return
+    end
+
+    -- 9. 按行读取测试
+    local line_file = dir_path .. "/testline"
+    file = io.open(line_file, "w")
+    if file then
+        file:write("abc\n")
+        file:write("123\n")
+        file:write("wendal\n")
+        file:close()
+        log.info("文件创建", "路径:" .. line_file, "写入3行文本")
+    else
+        log.error("文件创建", "无法创建文件", "路径:" .. line_file)
+        return
+    end
+
+    file = io.open(line_file, "r")
+    if file then
+        log.info("按行读取", "路径:" .. line_file, "第1行:", file:read("*l"))
+        log.info("按行读取", "路径:" .. line_file, "第2行:", file:read("*l"))
+        log.info("按行读取", "路径:" .. line_file, "第3行:", file:read("*l"))
+        file:close()
+    else
+        log.error("按行读取", "无法打开文件", "路径:" .. line_file)
+        return
+    end
+
+    -- 10. 文件重命名
+    local old_path = append_file
+    local new_path = dir_path .. "/renamed_file.txt"
+    local success, err = os.rename(old_path, new_path)
+    if success then
+        log.info("os.rename", "文件重命名成功", "原路径:" .. old_path, "新路径:" .. new_path)
+
+        -- 验证重命名结果
+        if io.exists(new_path) and not io.exists(old_path) then
+            log.info("验证结果", "重命名验证成功", "新文件存在", "原文件不存在")
+        else
+            log.error("验证结果", "重命名验证失败")
+        end
+    else
+        log.error("os.rename", "重命名失败", "错误:" .. tostring(err), "原路径:" .. old_path)
+        return
+    end
+
+    -- 11. 列举目录内容
+    log.info("目录操作", "===== 开始目录列举 =====")
+
+    local ret, data = io.lsdir(dir_path, 50, 0)
+    if ret then
+        log.info("fs", "lsdir", json.encode(data))
+    else
+        log.info("fs", "lsdir", "fail", ret, data)
+        return
+    end
+
+    -- 12. 删除文件测试
+    if os.remove(new_path) then
+        log.info("os.remove", "文件删除成功", "路径:" .. new_path)
+        if not io.exists(new_path) then
+            log.info("验证结果", "renamed_file.txt文件删除验证成功")
+        else
+            log.error("验证结果", "renamed_file.txt文件删除验证失败")
+        end
+    else
+        log.error("os.remove", "renamed_file.txt文件删除失败", "路径:" .. new_path)
+        return
+    end
+
+    if os.remove(line_file) then
+        log.info("os.remove", "testline文件删除成功", "路径:" .. line_file)
+        if not io.exists(line_file) then
+            log.info("验证结果", "testline文件删除验证成功")
+        else
+            log.error("验证结果", "testline文件删除验证失败")
+        end
+    else
+        log.error("os.remove", "testline文件删除失败", "路径:" .. line_file)
+        return
+    end
+
+    if os.remove(file_path) then
+        log.info("os.remove", "文件删除成功", "路径:" .. file_path)
+        if not io.exists(file_path) then
+            log.info("验证结果", "boottime文件删除验证成功")
+        else
+            log.error("验证结果", "boottime文件删除验证失败")
+        end
+    else
+        log.error("os.remove", "boottime文件删除失败", "路径:" .. file_path)
+        return
+    end
+
+    -- 13. 删除目录
+    if io.rmdir(dir_path) then
+        log.info("io.rmdir", "目录删除成功", "路径:" .. dir_path)
+        if not io.dexist(dir_path) then
+            log.info("验证结果", "目录删除验证成功")
+        else
+            log.error("验证结果", "目录删除验证失败")
+        end
+    else
+        log.error("io.rmdir", "目录删除失败", "路径:" .. dir_path)
+        return
+    end
+
+    -- 再次获取文件系统信息,查看空间变化
+    local final_success, final_total_blocks, final_used_blocks, final_block_size, final_fs_type =  io.fsstat(base_path)
+    if final_success then
+        log.info(" io.fsstat", "操作后文件系统信息:", 
+                 "总空间=" .. final_total_blocks .. "块", 
+                 "已用=" .. final_used_blocks .. "块", 
+                 "块大小=" .. final_block_size.."字节",
+                 "类型=" .. final_fs_type)
+    end
+
+    log.info("文件系统操作", "===== 文件系统操作完成 =====")
+end
+
+sys.taskInit(flash_fs_io_task)

+ 74 - 0
module/Air780EPM/demo/fs_io/http_download_flash.lua

@@ -0,0 +1,74 @@
+--[[
+@module http_download_flash
+@summary HTTP下载文件到内置Flash模块
+@version 1.0.0
+@date    2025.09.23
+@author  王棚嶙
+@usage
+本文件演示的功能为通过HTTP下载文件到内置Flash中:
+1. 网络就绪检测
+2. 创建HTTP下载任务并等待完成
+3. 记录下载结果
+4. 获取并记录文件大小(使用io.fileSize)
+本文件没有对外接口,直接在main.lua中require "http_download_flash"即可
+]]
+
+local function http_download_flash_task()
+    -- 阶段1: 网络就绪检测
+    while not socket.adapter(socket.dft()) do
+        log.warn("HTTP下载", "等待网络连接", socket.dft())
+        sys.waitUntil("IP_READY", 1000)
+    end
+
+    log.info("HTTP下载", "网络已就绪", socket.dft())
+
+    -- 阶段2: 执行下载任务
+    log.info("HTTP下载", "开始下载任务")
+
+    -- 创建下载目录
+    local download_dir = "/downloads"
+    if not io.dexist(download_dir) then
+        io.mkdir(download_dir)
+    end
+
+    -- 核心下载操作开始
+    local code, headers, body_size = http.request("GET",
+                                    "https://gitee.com/openLuat/LuatOS/raw/master/module/Air780EHM_Air780EHV_Air780EGH/demo/audio/sample-6s.mp3",
+                                    nil, nil, {dst = download_dir .. "/sample-6s.mp3"}).wait()
+
+    -- 阶段3: 记录下载结果
+    log.info("HTTP下载", "下载完成", 
+        code == 200 and "success" or "error", 
+        code, 
+        json.encode(headers or {}), 
+        body_size) 
+        
+    if code == 200 then
+        -- 获取实际文件大小 (使用io.fileSize接口)
+        local actual_size = io.fileSize(download_dir .. "/sample-6s.mp3")
+        if not actual_size then
+            -- 备用方案
+            actual_size = io.fileSize(download_dir .. "/sample-6s.mp3")
+        end
+        
+        log.info("HTTP下载", "文件大小验证", "预期:", body_size, "实际:", actual_size)
+        
+        if actual_size ~= body_size then
+            log.error("HTTP下载", "文件大小不一致", "预期:", body_size, "实际:", actual_size)
+        end
+        
+        -- 展示下载后的文件系统状态
+        local success, total_blocks, used_blocks, block_size, fs_type =  io.fsstat("/")
+        if success then
+            log.info("HTTP下载", "下载后文件系统信息:", 
+                     "总空间=" .. total_blocks .. "块", 
+                     "已用=" .. used_blocks .. "块", 
+                     "块大小=" .. block_size.."字节",
+                     "类型=" .. fs_type)
+        end
+    end
+
+end
+
+-- 创建下载任务
+sys.taskInit(http_download_flash_task)

+ 78 - 0
module/Air780EPM/demo/fs_io/main.lua

@@ -0,0 +1,78 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@version 001.000.000
+@date    2025.09.23
+@author  王棚嶙
+@usage
+本 Demo 演示了在Air780EPM内置Flash文件系统中的完整操作流程:
+1. 基础操作:看门狗守护机制
+2. 文件系统操作:
+   - 文件系统信息查询( io.fsstat)
+   - 文件大小获取(io.fileSize)
+   - 文件创建/读写/追加
+   - 目录创建/删除
+   - 文件重命名/删除
+   - 文件存在性检查
+3. 下载功能:
+   - 网络检测与HTTP文件下载到内置Flash
+]]
+
+--[[
+必须定义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 = "flash_fs_io_demo"
+VERSION = "001.000.000"
+
+-- 在日志中打印项目名和项目版本号
+log.info("main", PROJECT, VERSION)
+
+-- 添加硬狗防止程序卡死
+if wdt then
+    -- 初始化watchdog设置为9s
+    wdt.init(9000)
+    -- 3s喂一次狗 
+    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)
+
+--[[在加载以下两个功能时,建议分别打开进行测试,因为文件操作和http下载功能是异步操作。放到一个项目中,如果加载的时间点是随机的,就会出现哪个任务先抢到CPU时间片,哪个就先执行,不符合正常的业务逻辑,用户在参考编程的时候也要注意。]]
+
+-- 加载内置Flash文件系统操作演示模块
+require "flash_fs_io"
+-- 加载HTTP下载存入内置Flash功能演示模块
+-- require "http_download_flash"
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+-- sys.run()之后后面不要加任何语句!!!!!
+sys.run()

+ 141 - 0
module/Air780EPM/demo/fs_io/readme.md

@@ -0,0 +1,141 @@
+## **功能模块介绍**
+
+本 Demo 演示了在Air780EPM内置Flash文件系统中的完整操作流程,覆盖了从文件系统读写到高级文件操作的完整功能链。项目分为两个核心模块:
+
+1、main.lua:主程序入口 <br> 
+2、flash_fs_io.lua:内置Flash文件系统的操作测试流程模块,实现文件系统管理、文件操作和目录管理功能。<br> 
+3、http_download_flash.lua:HTTP下载模块,演示HTTP下载文件到内置Flash中的功能
+
+## **演示功能概述**
+
+### 1、主程序入口模块(main.lua)
+
+- 初始化项目信息和版本号
+- 初始化看门狗,并定时喂狗
+- 启动一个循环定时器,每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况方便分析内存使用是否有异常
+- 加载flash_fs_io模块(通过require "flash_fs_io")
+- 加载http_download_flash模块(通过require "http_download_flash")
+- 最后运行sys.run()。
+
+### 2、内置Flash文件系统演示模块(flash_fs_io.lua)
+
+#### 文件操作
+- 获取文件系统信息( io.fsstat)
+- 创建目录:io.mkdir("/flash_demo")
+- 创建/写入文件: io.open("/flash_demo/boottime", "wb")
+- 检查文件存在: io.exists(file_path)
+- 获取文件大小:io.fileSize(file_path)
+- 读取文件内容: io.open(file_path, "rb"):read("*a")
+- 启动计数文件: 记录设备启动次数
+- 文件追加: io.open(append_file, "a+")
+- 按行读取: file:read("*l")
+- 文件关闭: file:close()
+- 文件重命名: os.rename(old_path, new_path)
+- 列举目录: io.lsdir(dir_path)
+- 删除文件: os.remove(file_path)
+- 删除目录: io.rmdir(dir_path)
+
+### 3、HTTP下载功能 (http_download_flash.lua)
+
+
+#### 网络就绪检测
+
+- 1秒循环等待IP就绪
+- 网络故障处理机制
+
+#### 安全下载
+
+- HTTP下载
+
+#### 结果处理
+
+- 下载状态码解析
+- 自动文件大小验证
+- 获取文件系统信息( io.fsstat)
+
+## **演示硬件环境**
+
+1、Air780EPM核心板一块
+
+2、TYPE-C USB数据线一根
+
+3、SIM卡一张
+
+4、Air780EPM核心板和数据线的硬件接线方式为
+
+- Air780EPM核心板通过TYPE-C USB口供电;(核心板USB旁边的开关拨到on一端)
+
+- TYPE-C USB数据线直接插到核心板的TYPE-C USB座子,另外一端连接电脑USB口;
+
+## **演示软件环境**
+
+1、Luatools下载调试工具:https://docs.openluat.com/air780epm/common/Luatools/
+
+2、内核固件版本:https://docs.openluat.com/air780epm/luatos/firmware/version/
+
+## **演示核心步骤**
+
+1、搭建好硬件环境
+
+2、通过Luatools将demo与固件烧录到开发板中
+
+3、烧录好后,板子开机将会在Luatools上看到如下打印
+
+```lua
+
+(1)文件操作演示
+[2025-10-22 16:04:28.032][000000000.214] I/user.文件系统操作 ===== 开始文件系统操作 =====
+[2025-10-22 16:04:28.064][000000000.218] I/user. io.fsstat成功: 总空间=42块 已用=4块 块大小=4096字节 类型=lfs
+[2025-10-22 16:04:28.085][000000000.319] I/user.io.mkdir 目录创建成功 路径:/flash_demo
+[2025-10-22 16:04:28.105][000000000.328] I/user.文件创建 文件写入成功 路径:/flash_demo/boottime
+[2025-10-22 16:04:28.114][000000000.331] I/user.io.exists 文件存在 路径:/flash_demo/boottime
+[2025-10-22 16:04:28.130][000000000.334] I/user.io.fileSize 文件大小:59字节 路径:/flash_demo/boottime
+[2025-10-22 16:04:28.142][000000000.337] I/user.文件读取 路径:/flash_demo/boottime 内容:这是内置Flash文件系统API文档示例的测试内容
+[2025-10-22 16:04:28.167][000000000.340] I/user.启动计数 文件内容: 这是内置Flash文件系统API文档示例的测试内容 十六进制: E8BF99E698AFE58685E7BDAE466C617368E69687E4BBB6E7B3BBE7BB9F415049E69687E6A1A3E7A4BAE4BE8BE79A84E6B58BE8AF95E58685E5AEB9 118
+[2025-10-22 16:04:28.192][000000000.340] I/user.启动计数 当前值: 0
+[2025-10-22 16:04:28.217][000000000.340] I/user.启动计数 更新值: 1
+[2025-10-22 16:04:28.221][000000000.345] I/user.文件写入 路径:/flash_demo/boottime 内容: 1
+[2025-10-22 16:04:28.234][000000000.357] I/user.文件创建 路径:/flash_demo/test_a 初始内容:ABC
+[2025-10-22 16:04:28.242][000000000.360] I/user.文件追加 路径:/flash_demo/test_a 追加内容:def
+[2025-10-22 16:04:28.248][000000000.363] I/user.文件验证 路径:/flash_demo/test_a 内容:ABCdef 结果: 成功
+[2025-10-22 16:04:28.253][000000000.367] I/user.文件创建 路径:/flash_demo/testline 写入3行文本
+[2025-10-22 16:04:28.271][000000000.370] I/user.按行读取 路径:/flash_demo/testline 第1行: abc
+[2025-10-22 16:04:28.279][000000000.370] I/user.按行读取 路径:/flash_demo/testline 第2行: 123
+[2025-10-22 16:04:28.302][000000000.371] I/user.按行读取 路径:/flash_demo/testline 第3行: wendal
+[2025-10-22 16:04:28.331][000000000.377] I/user.os.rename 文件重命名成功 原路径:/flash_demo/test_a 新路径:/flash_demo/renamed_file.txt
+[2025-10-22 16:04:28.347][000000000.383] D/vfs fopen /flash_demo/test_a r not found
+[2025-10-22 16:04:28.361][000000000.383] I/user.验证结果 重命名验证成功 新文件存在 原文件不存在
+[2025-10-22 16:04:28.382][000000000.383] I/user.目录操作 ===== 开始目录列举 =====
+[2025-10-22 16:04:28.393][000000000.396] I/user.fs lsdir [{"name":"boottime","size":1,"type":0},{"name":"renamed_file.txt","size":6,"type":0},{"name":"testline","size":15,"type":0}]
+[2025-10-22 16:04:28.417][000000000.400] I/user.os.remove 文件删除成功 路径:/flash_demo/renamed_file.txt
+[2025-10-22 16:04:28.435][000000000.403] D/vfs fopen /flash_demo/renamed_file.txt r not found
+[2025-10-22 16:04:28.449][000000000.403] I/user.验证结果 renamed_file.txt文件删除验证成功
+[2025-10-22 16:04:28.469][000000000.407] I/user.os.remove testline文件删除成功 路径:/flash_demo/testline
+[2025-10-22 16:04:28.479][000000000.410] D/vfs fopen /flash_demo/testline r not found
+[2025-10-22 16:04:28.489][000000000.411] I/user.验证结果 testline文件删除验证成功
+[2025-10-22 16:04:28.507][000000000.417] I/user.os.remove 文件删除成功 路径:/flash_demo/boottime
+[2025-10-22 16:04:28.514][000000000.420] D/vfs fopen /flash_demo/boottime r not found
+[2025-10-22 16:04:28.519][000000000.421] I/user.验证结果 boottime文件删除验证成功
+[2025-10-22 16:04:28.532][000000000.427] I/user.io.rmdir 目录删除成功 路径:/flash_demo
+[2025-10-22 16:04:28.538][000000000.430] I/user.验证结果 目录删除验证成功
+[2025-10-22 16:04:28.547][000000000.435] I/user. io.fsstat 操作后文件系统信息: 总空间=42块 已用=4块 块大小=4096字节 类型=lfs
+[2025-10-22 16:04:28.554][000000000.435] I/user.文件系统操作 ===== 文件系统操作完成 =====
+
+
+
+
+
+(2)网络连接与HTTP下载
+[2025-10-22 15:34:04.507][000000007.471] I/user.HTTP下载 网络已就绪 1 3
+[2025-10-22 15:34:04.550][000000007.471] I/user.HTTP下载 开始下载任务
+[2025-10-22 15:34:04.579][000000007.478] dns_run 676:gitee.com state 0 id 1 ipv6 0 use dns server2, try 0
+[2025-10-22 15:34:04.604][000000007.508] D/mobile TIME_SYNC 0
+[2025-10-22 15:34:04.734][000000007.517] dns_run 693:dns all done ,now stop
+[2025-10-22 15:34:06.390][000000009.741] I/user.HTTP下载 下载完成 success 200 
+[2025-10-22 15:34:06.422][000000009.741] {"Age":"0","Cache-Control":"public, max-age=60","Via":"1.1 varnish","Transfer-Encoding":"chunked","Date":"Wed, 22 Oct 2025 07:34:04 GMT","Access-Control-Allow-Credentials":"true","Vary":"Accept-Encoding","X-Served-By":"cache-ffe9","X-Gitee-Server":"http-pilot 1.9.21","Connection":"keep-alive","Server":"ADAS\/1.0.214","Access-Control-Allow-Headers":"Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With,X-CustomHeader,Content-Range,Range,Set-Language","Content-Security-Policy":"default-src 'none'; style-src 'unsafe-inline'; sandbox","X-Request-Id":"fa536af1-51bd-400f-8d4b-7322355a9db2","Accept-Ranges":"bytes","Etag":"W\/\"2aaa2788d394a924e258d6f26ad78b8c948950f5\"","Content-Type":"text\/plain; charset=utf-8","Access-Control-Allow-Methods":"GET, POST, PUT, PATCH, DELETE, OPTIONS","X-Frame-Options":"DENY","X-Cache":"MISS","Set-Cookie":"BEC=1f1759df3ccd099821dcf0da6feb0357;Path=\/;Max-Age=126000"}
+[2025-10-22 15:34:06.477][000000009.742]  103070
+[2025-10-22 15:34:06.492][000000009.745] I/user.HTTP下载 文件大小验证 预期: 103070 实际: 103070
+[2025-10-22 15:34:06.525][000000009.751] I/user.HTTP下载 下载后文件系统信息: 总空间=42块 已用=32块 块大小=4096字节 类型=lfs
+
+
+```

+ 282 - 0
module/Air8000/demo/fs_io/flash_fs_io.lua

@@ -0,0 +1,282 @@
+--[[
+@module  flash_fs_io
+@summary 内置Flash文件系统操作测试模块
+@version 1.0.0
+@date    2025.09.23
+@author  王棚嶙
+@usage
+本文件为内置Flash文件系统的操作测试流程:
+1. 获取文件系统信息( io.fsstat)
+2. 创建目录
+3. 创建并写入文件
+4. 检查文件是否存在
+5. 获取文件大小(io.fileSize)
+6. 读取文件内容
+7. 启动计数文件操作
+8. 文件追加测试
+9. 按行读取测试
+10. 文件重命名
+11. 列举目录内容
+12. 删除文件
+13. 删除目录
+本文件没有对外接口,直接在main.lua中require "flash_fs_io"就可以加载运行
+]]
+
+function flash_fs_io_task()
+    -- 使用内置Flash文件系统,根目录为"/",
+    local base_path = "/"
+    -- 创建一个目录
+    local demo_dir = "flash_demo"
+    -- 文件名
+    local dir_path = base_path .. demo_dir
+
+    -- ########## 开始进行内置Flash文件系统操作 ##########
+    log.info("文件系统操作", "===== 开始文件系统操作 =====")
+
+    -- 1. 获取文件系统信息 (使用 io.fsstat接口)
+    local success, total_blocks, used_blocks, block_size, fs_type  =  io.fsstat(base_path)
+    if success then
+        log.info(" io.fsstat成功:", 
+            "总空间=" .. total_blocks .. "块", 
+            "已用=" .. used_blocks .. "块", 
+            "块大小=" .. block_size.."字节",
+            "类型=" .. fs_type)
+    else
+        log.error(" io.fsstat", "获取文件系统信息失败")
+        return
+    end
+
+    -- 2. 创建目录
+    -- 如果目录不存在,则创建目录
+    if not io.dexist(dir_path) then
+        -- 创建目录
+        if io.mkdir(dir_path) then
+            log.info("io.mkdir", "目录创建成功", "路径:" .. dir_path)
+        else
+            log.error("io.mkdir", "目录创建失败", "路径:" .. dir_path)
+            return
+        end
+    else
+        log.warn("io.mkdir", "目录已存在,跳过创建", "路径:" .. dir_path)
+    end
+
+    -- 3. 创建并写入文件
+    local file_path = dir_path .. "/boottime"
+    local file = io.open(file_path, "wb")
+    if file then
+        file:write("这是内置Flash文件系统API文档示例的测试内容")
+        file:close()
+        log.info("文件创建", "文件写入成功", "路径:" .. file_path)
+    else
+        log.error("文件创建", "文件创建失败", "路径:" .. file_path)
+        return
+    end
+
+    -- 4. 检查文件是否存在
+    if io.exists(file_path) then
+        log.info("io.exists", "文件存在", "路径:" .. file_path)
+    else
+        log.error("io.exists", "文件不存在", "路径:" .. file_path)
+        return
+    end
+
+    -- 5. 获取文件大小 (使用io.fileSize接口)
+    local file_size = io.fileSize(file_path)
+    if file_size then
+        log.info("io.fileSize", "文件大小:" .. file_size .. "字节", "路径:" .. file_path)
+    else
+        log.error("io.fileSize", "获取文件大小失败", "路径:" .. file_path)
+        return
+    end
+
+    -- 6. 读取文件内容
+    file = io.open(file_path, "rb")
+    if file then
+        local content = file:read("*a")
+        log.info("文件读取", "路径:" .. file_path, "内容:" .. content)
+        file:close()
+    else
+        log.error("文件操作", "无法打开文件读取内容", "路径:" .. file_path)
+        return
+    end
+
+    -- 7. 启动计数文件操作
+    local count = 0
+    file = io.open(file_path, "rb")
+    if file then
+        local data = file:read("*a")
+        log.info("启动计数", "文件内容:", data, "十六进制:", data:toHex())
+        count = tonumber(data) or 0
+        file:close()
+    else
+        log.warn("启动计数", "文件不存在或无法打开")
+    end
+
+    log.info("启动计数", "当前值:", count)
+    count = count + 1
+    log.info("启动计数", "更新值:", count)
+
+    file = io.open(file_path, "wb")
+    if file then
+        file:write(tostring(count))
+        file:close()
+        log.info("文件写入", "路径:" .. file_path, "内容:", count)
+    else
+        log.error("文件写入", "无法打开文件", "路径:" .. file_path)
+        return
+    end
+
+    -- 8. 文件追加测试
+    local append_file = dir_path .. "/test_a"
+    os.remove(append_file) -- 清理旧文件
+
+    file = io.open(append_file, "wb")
+    if file then
+        file:write("ABC")
+        file:close()
+        log.info("文件创建", "路径:" .. append_file, "初始内容:ABC")
+    else
+        log.error("文件创建", "无法创建文件", "路径:" .. append_file)
+        return
+    end
+
+    file = io.open(append_file, "a+")
+    if file then
+        file:write("def")
+        file:close()
+        log.info("文件追加", "路径:" .. append_file, "追加内容:def")
+    else
+        log.error("文件追加", "无法打开文件进行追加", "路径:" .. append_file)
+        return
+    end
+
+    -- 验证追加结果
+    file = io.open(append_file, "r")
+    if file then
+        local data = file:read("*a")
+        log.info("文件验证", "路径:" .. append_file, "内容:" .. data, "结果:",
+            data == "ABCdef" and "成功" or "失败")
+        file:close()
+    else
+        log.error("文件验证", "无法打开文件进行验证", "路径:" .. append_file)
+        return
+    end
+
+    -- 9. 按行读取测试
+    local line_file = dir_path .. "/testline"
+    file = io.open(line_file, "w")
+    if file then
+        file:write("abc\n")
+        file:write("123\n")
+        file:write("wendal\n")
+        file:close()
+        log.info("文件创建", "路径:" .. line_file, "写入3行文本")
+    else
+        log.error("文件创建", "无法创建文件", "路径:" .. line_file)
+        return
+    end
+
+    file = io.open(line_file, "r")
+    if file then
+        log.info("按行读取", "路径:" .. line_file, "第1行:", file:read("*l"))
+        log.info("按行读取", "路径:" .. line_file, "第2行:", file:read("*l"))
+        log.info("按行读取", "路径:" .. line_file, "第3行:", file:read("*l"))
+        file:close()
+    else
+        log.error("按行读取", "无法打开文件", "路径:" .. line_file)
+        return
+    end
+
+    -- 10. 文件重命名
+    local old_path = append_file
+    local new_path = dir_path .. "/renamed_file.txt"
+    local success, err = os.rename(old_path, new_path)
+    if success then
+        log.info("os.rename", "文件重命名成功", "原路径:" .. old_path, "新路径:" .. new_path)
+
+        -- 验证重命名结果
+        if io.exists(new_path) and not io.exists(old_path) then
+            log.info("验证结果", "重命名验证成功", "新文件存在", "原文件不存在")
+        else
+            log.error("验证结果", "重命名验证失败")
+        end
+    else
+        log.error("os.rename", "重命名失败", "错误:" .. tostring(err), "原路径:" .. old_path)
+        return
+    end
+
+    -- 11. 列举目录内容
+    log.info("目录操作", "===== 开始目录列举 =====")
+
+    local ret, data = io.lsdir(dir_path, 50, 0)
+    if ret then
+        log.info("fs", "lsdir", json.encode(data))
+    else
+        log.info("fs", "lsdir", "fail", ret, data)
+        return
+    end
+
+    -- 12. 删除文件测试
+    if os.remove(new_path) then
+        log.info("os.remove", "文件删除成功", "路径:" .. new_path)
+        if not io.exists(new_path) then
+            log.info("验证结果", "renamed_file.txt文件删除验证成功")
+        else
+            log.error("验证结果", "renamed_file.txt文件删除验证失败")
+        end
+    else
+        log.error("os.remove", "renamed_file.txt文件删除失败", "路径:" .. new_path)
+        return
+    end
+
+    if os.remove(line_file) then
+        log.info("os.remove", "testline文件删除成功", "路径:" .. line_file)
+        if not io.exists(line_file) then
+            log.info("验证结果", "testline文件删除验证成功")
+        else
+            log.error("验证结果", "testline文件删除验证失败")
+        end
+    else
+        log.error("os.remove", "testline文件删除失败", "路径:" .. line_file)
+        return
+    end
+
+    if os.remove(file_path) then
+        log.info("os.remove", "文件删除成功", "路径:" .. file_path)
+        if not io.exists(file_path) then
+            log.info("验证结果", "boottime文件删除验证成功")
+        else
+            log.error("验证结果", "boottime文件删除验证失败")
+        end
+    else
+        log.error("os.remove", "boottime文件删除失败", "路径:" .. file_path)
+        return
+    end
+
+    -- 13. 删除目录
+    if io.rmdir(dir_path) then
+        log.info("io.rmdir", "目录删除成功", "路径:" .. dir_path)
+        if not io.dexist(dir_path) then
+            log.info("验证结果", "目录删除验证成功")
+        else
+            log.error("验证结果", "目录删除验证失败")
+        end
+    else
+        log.error("io.rmdir", "目录删除失败", "路径:" .. dir_path)
+        return
+    end
+
+    -- 再次获取文件系统信息,查看空间变化
+    local final_success, final_total_blocks, final_used_blocks, final_block_size, final_fs_type =  io.fsstat(base_path)
+    if final_success then
+        log.info(" io.fsstat", "操作后文件系统信息:", 
+                 "总空间=" .. final_total_blocks .. "块", 
+                 "已用=" .. final_used_blocks .. "块", 
+                 "块大小=" .. final_block_size.."字节",
+                 "类型=" .. final_fs_type)
+    end
+
+    log.info("文件系统操作", "===== 文件系统操作完成 =====")
+end
+
+sys.taskInit(flash_fs_io_task)

+ 74 - 0
module/Air8000/demo/fs_io/http_download_flash.lua

@@ -0,0 +1,74 @@
+--[[
+@module http_download_flash
+@summary HTTP下载文件到内置Flash模块
+@version 1.0.0
+@date    2025.09.23
+@author  王棚嶙
+@usage
+本文件演示的功能为通过HTTP下载文件到内置Flash中:
+1. 网络就绪检测
+2. 创建HTTP下载任务并等待完成
+3. 记录下载结果
+4. 获取并记录文件大小(使用io.fileSize)
+本文件没有对外接口,直接在main.lua中require "http_download_flash"即可
+]]
+
+local function http_download_flash_task()
+    -- 阶段1: 网络就绪检测
+    while not socket.adapter(socket.dft()) do
+        log.warn("HTTP下载", "等待网络连接", socket.dft())
+        sys.waitUntil("IP_READY", 1000)
+    end
+
+    log.info("HTTP下载", "网络已就绪", socket.dft())
+
+    -- 阶段2: 执行下载任务
+    log.info("HTTP下载", "开始下载任务")
+
+    -- 创建下载目录
+    local download_dir = "/downloads"
+    if not io.dexist(download_dir) then
+        io.mkdir(download_dir)
+    end
+
+    -- 核心下载操作开始
+    local code, headers, body_size = http.request("GET",
+                                    "https://gitee.com/openLuat/LuatOS/raw/master/module/Air780EHM_Air780EHV_Air780EGH/demo/audio/sample-6s.mp3",
+                                    nil, nil, {dst = download_dir .. "/sample-6s.mp3"}).wait()
+
+    -- 阶段3: 记录下载结果
+    log.info("HTTP下载", "下载完成", 
+        code == 200 and "success" or "error", 
+        code, 
+        json.encode(headers or {}), 
+        body_size) 
+        
+    if code == 200 then
+        -- 获取实际文件大小 (使用io.fileSize接口)
+        local actual_size = io.fileSize(download_dir .. "/sample-6s.mp3")
+        if not actual_size then
+            -- 备用方案
+            actual_size = io.fileSize(download_dir .. "/sample-6s.mp3")
+        end
+        
+        log.info("HTTP下载", "文件大小验证", "预期:", body_size, "实际:", actual_size)
+        
+        if actual_size ~= body_size then
+            log.error("HTTP下载", "文件大小不一致", "预期:", body_size, "实际:", actual_size)
+        end
+        
+        -- 展示下载后的文件系统状态
+        local success, total_blocks, used_blocks, block_size, fs_type =  io.fsstat("/")
+        if success then
+            log.info("HTTP下载", "下载后文件系统信息:", 
+                     "总空间=" .. total_blocks .. "块", 
+                     "已用=" .. used_blocks .. "块", 
+                     "块大小=" .. block_size.."字节",
+                     "类型=" .. fs_type)
+        end
+    end
+
+end
+
+-- 创建下载任务
+sys.taskInit(http_download_flash_task)

+ 78 - 0
module/Air8000/demo/fs_io/main.lua

@@ -0,0 +1,78 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@version 001.000.000
+@date    2025.09.23
+@author  王棚嶙
+@usage
+本 Demo 演示了在Air8000内置Flash文件系统中的完整操作流程:
+1. 基础操作:看门狗守护机制
+2. 文件系统操作:
+   - 文件系统信息查询( io.fsstat)
+   - 文件大小获取(io.fileSize)
+   - 文件创建/读写/追加
+   - 目录创建/删除
+   - 文件重命名/删除
+   - 文件存在性检查
+3. 下载功能:
+   - 网络检测与HTTP文件下载到内置Flash
+]]
+
+--[[
+必须定义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 = "flash_fs_io_demo"
+VERSION = "001.000.000"
+
+-- 在日志中打印项目名和项目版本号
+log.info("main", PROJECT, VERSION)
+
+-- 添加硬狗防止程序卡死
+if wdt then
+    -- 初始化watchdog设置为9s
+    wdt.init(9000)
+    -- 3s喂一次狗 
+    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)
+
+--[[在加载以下两个功能时,建议分别打开进行测试,因为文件操作和http下载功能是异步操作。放到一个项目中,如果加载的时间点是随机的,就会出现哪个任务先抢到CPU时间片,哪个就先执行,不符合正常的业务逻辑,用户在参考编程的时候也要注意。]]
+
+-- 加载内置Flash文件系统操作演示模块
+require "flash_fs_io"
+-- 加载HTTP下载存入内置Flash功能演示模块
+-- require "http_download_flash"
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+-- sys.run()之后后面不要加任何语句!!!!!
+sys.run()

+ 139 - 0
module/Air8000/demo/fs_io/readme.md

@@ -0,0 +1,139 @@
+## **功能模块介绍**
+
+本 Demo 演示了在Air8000内置Flash文件系统中的完整操作流程,覆盖了从文件系统读写到高级文件操作的完整功能链。项目分为两个核心模块:
+
+1、main.lua:主程序入口 <br> 
+2、flash_fs_io.lua:内置Flash文件系统的操作测试流程模块,实现文件系统管理、文件操作和目录管理功能。<br> 
+3、http_download_flash.lua:HTTP下载模块,演示HTTP下载文件到内置Flash中的功能
+
+## **演示功能概述**
+
+### 1、主程序入口模块(main.lua)
+
+- 初始化项目信息和版本号
+- 初始化看门狗,并定时喂狗
+- 启动一个循环定时器,每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况方便分析内存使用是否有异常
+- 加载flash_fs_io模块(通过require "flash_fs_io")
+- 加载http_download_flash模块(通过require "http_download_flash")
+- 最后运行sys.run()。
+
+### 2、内置Flash文件系统演示模块(flash_fs_io.lua)
+
+#### 文件操作
+- 获取文件系统信息( io.fsstat)
+- 创建目录:io.mkdir("/flash_demo")
+- 创建/写入文件: io.open("/flash_demo/boottime", "wb")
+- 检查文件存在: io.exists(file_path)
+- 获取文件大小:io.fileSize(file_path)
+- 读取文件内容: io.open(file_path, "rb"):read("*a")
+- 启动计数文件: 记录设备启动次数
+- 文件追加: io.open(append_file, "a+")
+- 按行读取: file:read("*l")
+- 文件关闭: file:close()
+- 文件重命名: os.rename(old_path, new_path)
+- 列举目录: io.lsdir(dir_path)
+- 删除文件: os.remove(file_path)
+- 删除目录: io.rmdir(dir_path)
+
+### 3、HTTP下载功能 (http_download_flash.lua)
+
+
+#### 网络就绪检测
+
+- 1秒循环等待IP就绪
+- 网络故障处理机制
+
+#### 安全下载
+
+- HTTP下载
+
+#### 结果处理
+
+- 下载状态码解析
+- 自动文件大小验证
+- 获取文件系统信息( io.fsstat)
+
+## **演示硬件环境**
+
+1、Air8000整机开发板一块
+
+2、sim卡一张
+
+3、TYPE-C USB数据线一根
+
+4、Air8000整机开发板和数据线的硬件接线方式为
+
+- Air8000整机开发板通过TYPE-C USB口供电;(USB旁边的开关拨到USB供电)
+- TYPE-C USB数据线直接插到Air8000整机开发板的TYPE-C USB座子,另外一端连接电脑USB口;
+
+## **演示软件环境**
+
+1、Luatools下载调试工具:https://docs.openluat.com/air780epm/common/Luatools/
+
+2、内核固件版本:https://docs.openluat.com/air8000/luatos/firmware/
+
+## **演示核心步骤**
+
+1、搭建好硬件环境
+
+2、通过Luatools将demo与固件烧录到开发板中
+
+3、烧录好后,板子开机将会在Luatools上看到如下打印
+
+```lua
+
+(1)文件操作演示
+[2025-10-22 15:23:25.096][000000000.595] I/user.文件系统操作 ===== 开始文件系统操作 =====
+[2025-10-22 15:23:25.104][000000000.601] I/user. io.fsstat成功: 总空间=192块 已用=20块 块大小=4096字节 类型=lfs
+[2025-10-22 15:23:25.118][000000000.644] I/user.io.mkdir 目录创建成功 路径:/flash_demo
+[2025-10-22 15:23:25.127][000000000.648] I/user.文件创建 文件写入成功 路径:/flash_demo/boottime
+[2025-10-22 15:23:25.145][000000000.651] I/user.io.exists 文件存在 路径:/flash_demo/boottime
+[2025-10-22 15:23:25.157][000000000.654] I/user.io.fileSize 文件大小:59字节 路径:/flash_demo/boottime
+[2025-10-22 15:23:25.165][000000000.657] I/user.文件读取 路径:/flash_demo/boottime 内容:这是内置Flash文件系统API文档示例的测试内容
+[2025-10-22 15:23:25.181][000000000.660] I/user.启动计数 文件内容: 这是内置Flash文件系统API文档示例的测试内容 十六进制: E8BF99E698AFE58685E7BDAE466C617368E69687E4BBB6E7B3BBE7BB9F415049E69687E6A1A3E7A4BAE4BE8BE79A84E6B58BE8AF95E58685E5AEB9 118
+[2025-10-22 15:23:25.189][000000000.660] I/user.启动计数 当前值: 0
+[2025-10-22 15:23:25.211][000000000.660] I/user.启动计数 更新值: 1
+[2025-10-22 15:23:25.217][000000000.663] I/user.文件写入 路径:/flash_demo/boottime 内容: 1
+[2025-10-22 15:23:25.224][000000000.669] I/user.文件创建 路径:/flash_demo/test_a 初始内容:ABC
+[2025-10-22 15:23:25.245][000000000.672] I/user.文件追加 路径:/flash_demo/test_a 追加内容:def
+[2025-10-22 15:23:25.251][000000000.675] I/user.文件验证 路径:/flash_demo/test_a 内容:ABCdef 结果: 成功
+[2025-10-22 15:23:25.267][000000000.678] I/user.文件创建 路径:/flash_demo/testline 写入3行文本
+[2025-10-22 15:23:25.277][000000000.681] I/user.按行读取 路径:/flash_demo/testline 第1行: abc
+[2025-10-22 15:23:25.285][000000000.682] I/user.按行读取 路径:/flash_demo/testline 第2行: 123
+[2025-10-22 15:23:25.295][000000000.682] I/user.按行读取 路径:/flash_demo/testline 第3行: wendal
+[2025-10-22 15:23:25.301][000000000.689] I/user.os.rename 文件重命名成功 原路径:/flash_demo/test_a 新路径:/flash_demo/renamed_file.txt
+[2025-10-22 15:23:25.312][000000000.694] D/vfs fopen /flash_demo/test_a r not found
+[2025-10-22 15:23:25.321][000000000.694] I/user.验证结果 重命名验证成功 新文件存在 原文件不存在
+[2025-10-22 15:23:25.340][000000000.695] I/user.目录操作 ===== 开始目录列举 =====
+[2025-10-22 15:23:25.348][000000000.706] I/user.fs lsdir [{"name":"boottime","size":1,"type":0},{"name":"renamed_file.txt","size":6,"type":0},{"name":"testline","size":15,"type":0}]
+[2025-10-22 15:23:25.359][000000000.710] I/user.os.remove 文件删除成功 路径:/flash_demo/renamed_file.txt
+[2025-10-22 15:23:25.366][000000000.713] D/vfs fopen /flash_demo/renamed_file.txt r not found
+[2025-10-22 15:23:25.373][000000000.713] I/user.验证结果 renamed_file.txt文件删除验证成功
+[2025-10-22 15:23:25.378][000000000.716] I/user.os.remove testline文件删除成功 路径:/flash_demo/testline
+[2025-10-22 15:23:25.390][000000000.719] D/vfs fopen /flash_demo/testline r not found
+[2025-10-22 15:23:25.395][000000000.719] I/user.验证结果 testline文件删除验证成功
+[2025-10-22 15:23:25.415][000000000.723] I/user.os.remove 文件删除成功 路径:/flash_demo/boottime
+[2025-10-22 15:23:25.423][000000000.726] D/vfs fopen /flash_demo/boottime r not found
+[2025-10-22 15:23:25.444][000000000.726] I/user.验证结果 boottime文件删除验证成功
+[2025-10-22 15:23:25.453][000000000.732] I/user.io.rmdir 目录删除成功 路径:/flash_demo
+[2025-10-22 15:23:25.464][000000000.734] I/user.验证结果 目录删除验证成功
+[2025-10-22 15:23:25.477][000000000.740] I/user. io.fsstat 操作后文件系统信息: 总空间=192块 已用=20块 块大小=4096字节 类型=lfs
+[2025-10-22 15:23:25.484][000000000.740] I/user.文件系统操作 ===== 文件系统操作完成 =====
+
+
+
+
+(2)网络连接与HTTP下载
+[2025-10-22 15:34:04.507][000000007.471] I/user.HTTP下载 网络已就绪 1 3
+[2025-10-22 15:34:04.550][000000007.471] I/user.HTTP下载 开始下载任务
+[2025-10-22 15:34:04.579][000000007.478] dns_run 676:gitee.com state 0 id 1 ipv6 0 use dns server2, try 0
+[2025-10-22 15:34:04.604][000000007.508] D/mobile TIME_SYNC 0
+[2025-10-22 15:34:04.734][000000007.517] dns_run 693:dns all done ,now stop
+[2025-10-22 15:34:06.390][000000009.741] I/user.HTTP下载 下载完成 success 200 
+[2025-10-22 15:34:06.422][000000009.741] {"Age":"0","Cache-Control":"public, max-age=60","Via":"1.1 varnish","Transfer-Encoding":"chunked","Date":"Wed, 22 Oct 2025 07:34:04 GMT","Access-Control-Allow-Credentials":"true","Vary":"Accept-Encoding","X-Served-By":"cache-ffe9","X-Gitee-Server":"http-pilot 1.9.21","Connection":"keep-alive","Server":"ADAS\/1.0.214","Access-Control-Allow-Headers":"Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With,X-CustomHeader,Content-Range,Range,Set-Language","Content-Security-Policy":"default-src 'none'; style-src 'unsafe-inline'; sandbox","X-Request-Id":"fa536af1-51bd-400f-8d4b-7322355a9db2","Accept-Ranges":"bytes","Etag":"W\/\"2aaa2788d394a924e258d6f26ad78b8c948950f5\"","Content-Type":"text\/plain; charset=utf-8","Access-Control-Allow-Methods":"GET, POST, PUT, PATCH, DELETE, OPTIONS","X-Frame-Options":"DENY","X-Cache":"MISS","Set-Cookie":"BEC=1f1759df3ccd099821dcf0da6feb0357;Path=\/;Max-Age=126000"}
+[2025-10-22 15:34:06.477][000000009.742]  103070
+[2025-10-22 15:34:06.492][000000009.745] I/user.HTTP下载 文件大小验证 预期: 103070 实际: 103070
+[2025-10-22 15:34:06.525][000000009.751] I/user.HTTP下载 下载后文件系统信息: 总空间=192块 已用=46块 块大小=4096字节 类型=lfs
+
+
+```

+ 282 - 0
module/Air8101/demo/fs_io/flash_fs_io.lua

@@ -0,0 +1,282 @@
+--[[
+@module  flash_fs_io
+@summary 内置Flash文件系统操作测试模块
+@version 1.0.0
+@date    2025.09.23
+@author  王棚嶙
+@usage
+本文件为内置Flash文件系统的操作测试流程:
+1. 获取文件系统信息( io.fsstat)
+2. 创建目录
+3. 创建并写入文件
+4. 检查文件是否存在
+5. 获取文件大小(io.fileSize)
+6. 读取文件内容
+7. 启动计数文件操作
+8. 文件追加测试
+9. 按行读取测试
+10. 文件重命名
+11. 列举目录内容
+12. 删除文件
+13. 删除目录
+本文件没有对外接口,直接在main.lua中require "flash_fs_io"就可以加载运行
+]]
+
+function flash_fs_io_task()
+    -- 使用内置Flash文件系统,根目录为"/",
+    local base_path = "/"
+    -- 创建一个目录
+    local demo_dir = "flash_demo"
+    -- 文件名
+    local dir_path = base_path .. demo_dir
+
+    -- ########## 开始进行内置Flash文件系统操作 ##########
+    log.info("文件系统操作", "===== 开始文件系统操作 =====")
+
+    -- 1. 获取文件系统信息 (使用 io.fsstat接口)
+    local success, total_blocks, used_blocks, block_size, fs_type  =  io.fsstat(base_path)
+    if success then
+        log.info(" io.fsstat成功:", 
+            "总空间=" .. total_blocks .. "块", 
+            "已用=" .. used_blocks .. "块", 
+            "块大小=" .. block_size.."字节",
+            "类型=" .. fs_type)
+    else
+        log.error(" io.fsstat", "获取文件系统信息失败")
+        return
+    end
+
+    -- 2. 创建目录
+    -- 如果目录不存在,则创建目录
+    if not io.dexist(dir_path) then
+        -- 创建目录
+        if io.mkdir(dir_path) then
+            log.info("io.mkdir", "目录创建成功", "路径:" .. dir_path)
+        else
+            log.error("io.mkdir", "目录创建失败", "路径:" .. dir_path)
+            return
+        end
+    else
+        log.warn("io.mkdir", "目录已存在,跳过创建", "路径:" .. dir_path)
+    end
+
+    -- 3. 创建并写入文件
+    local file_path = dir_path .. "/boottime"
+    local file = io.open(file_path, "wb")
+    if file then
+        file:write("这是内置Flash文件系统API文档示例的测试内容")
+        file:close()
+        log.info("文件创建", "文件写入成功", "路径:" .. file_path)
+    else
+        log.error("文件创建", "文件创建失败", "路径:" .. file_path)
+        return
+    end
+
+    -- 4. 检查文件是否存在
+    if io.exists(file_path) then
+        log.info("io.exists", "文件存在", "路径:" .. file_path)
+    else
+        log.error("io.exists", "文件不存在", "路径:" .. file_path)
+        return
+    end
+
+    -- 5. 获取文件大小 (使用io.fileSize接口)
+    local file_size = io.fileSize(file_path)
+    if file_size then
+        log.info("io.fileSize", "文件大小:" .. file_size .. "字节", "路径:" .. file_path)
+    else
+        log.error("io.fileSize", "获取文件大小失败", "路径:" .. file_path)
+        return
+    end
+
+    -- 6. 读取文件内容
+    file = io.open(file_path, "rb")
+    if file then
+        local content = file:read("*a")
+        log.info("文件读取", "路径:" .. file_path, "内容:" .. content)
+        file:close()
+    else
+        log.error("文件操作", "无法打开文件读取内容", "路径:" .. file_path)
+        return
+    end
+
+    -- 7. 启动计数文件操作
+    local count = 0
+    file = io.open(file_path, "rb")
+    if file then
+        local data = file:read("*a")
+        log.info("启动计数", "文件内容:", data, "十六进制:", data:toHex())
+        count = tonumber(data) or 0
+        file:close()
+    else
+        log.warn("启动计数", "文件不存在或无法打开")
+    end
+
+    log.info("启动计数", "当前值:", count)
+    count = count + 1
+    log.info("启动计数", "更新值:", count)
+
+    file = io.open(file_path, "wb")
+    if file then
+        file:write(tostring(count))
+        file:close()
+        log.info("文件写入", "路径:" .. file_path, "内容:", count)
+    else
+        log.error("文件写入", "无法打开文件", "路径:" .. file_path)
+        return
+    end
+
+    -- 8. 文件追加测试
+    local append_file = dir_path .. "/test_a"
+    os.remove(append_file) -- 清理旧文件
+
+    file = io.open(append_file, "wb")
+    if file then
+        file:write("ABC")
+        file:close()
+        log.info("文件创建", "路径:" .. append_file, "初始内容:ABC")
+    else
+        log.error("文件创建", "无法创建文件", "路径:" .. append_file)
+        return
+    end
+
+    file = io.open(append_file, "a+")
+    if file then
+        file:write("def")
+        file:close()
+        log.info("文件追加", "路径:" .. append_file, "追加内容:def")
+    else
+        log.error("文件追加", "无法打开文件进行追加", "路径:" .. append_file)
+        return
+    end
+
+    -- 验证追加结果
+    file = io.open(append_file, "r")
+    if file then
+        local data = file:read("*a")
+        log.info("文件验证", "路径:" .. append_file, "内容:" .. data, "结果:",
+            data == "ABCdef" and "成功" or "失败")
+        file:close()
+    else
+        log.error("文件验证", "无法打开文件进行验证", "路径:" .. append_file)
+        return
+    end
+
+    -- 9. 按行读取测试
+    local line_file = dir_path .. "/testline"
+    file = io.open(line_file, "w")
+    if file then
+        file:write("abc\n")
+        file:write("123\n")
+        file:write("wendal\n")
+        file:close()
+        log.info("文件创建", "路径:" .. line_file, "写入3行文本")
+    else
+        log.error("文件创建", "无法创建文件", "路径:" .. line_file)
+        return
+    end
+
+    file = io.open(line_file, "r")
+    if file then
+        log.info("按行读取", "路径:" .. line_file, "第1行:", file:read("*l"))
+        log.info("按行读取", "路径:" .. line_file, "第2行:", file:read("*l"))
+        log.info("按行读取", "路径:" .. line_file, "第3行:", file:read("*l"))
+        file:close()
+    else
+        log.error("按行读取", "无法打开文件", "路径:" .. line_file)
+        return
+    end
+
+    -- 10. 文件重命名
+    local old_path = append_file
+    local new_path = dir_path .. "/renamed_file.txt"
+    local success, err = os.rename(old_path, new_path)
+    if success then
+        log.info("os.rename", "文件重命名成功", "原路径:" .. old_path, "新路径:" .. new_path)
+
+        -- 验证重命名结果
+        if io.exists(new_path) and not io.exists(old_path) then
+            log.info("验证结果", "重命名验证成功", "新文件存在", "原文件不存在")
+        else
+            log.error("验证结果", "重命名验证失败")
+        end
+    else
+        log.error("os.rename", "重命名失败", "错误:" .. tostring(err), "原路径:" .. old_path)
+        return
+    end
+
+    -- 11. 列举目录内容
+    log.info("目录操作", "===== 开始目录列举 =====")
+
+    local ret, data = io.lsdir(dir_path, 50, 0)
+    if ret then
+        log.info("fs", "lsdir", json.encode(data))
+    else
+        log.info("fs", "lsdir", "fail", ret, data)
+        return
+    end
+
+    -- 12. 删除文件测试
+    if os.remove(new_path) then
+        log.info("os.remove", "文件删除成功", "路径:" .. new_path)
+        if not io.exists(new_path) then
+            log.info("验证结果", "renamed_file.txt文件删除验证成功")
+        else
+            log.error("验证结果", "renamed_file.txt文件删除验证失败")
+        end
+    else
+        log.error("os.remove", "renamed_file.txt文件删除失败", "路径:" .. new_path)
+        return
+    end
+
+    if os.remove(line_file) then
+        log.info("os.remove", "testline文件删除成功", "路径:" .. line_file)
+        if not io.exists(line_file) then
+            log.info("验证结果", "testline文件删除验证成功")
+        else
+            log.error("验证结果", "testline文件删除验证失败")
+        end
+    else
+        log.error("os.remove", "testline文件删除失败", "路径:" .. line_file)
+        return
+    end
+
+    if os.remove(file_path) then
+        log.info("os.remove", "文件删除成功", "路径:" .. file_path)
+        if not io.exists(file_path) then
+            log.info("验证结果", "boottime文件删除验证成功")
+        else
+            log.error("验证结果", "boottime文件删除验证失败")
+        end
+    else
+        log.error("os.remove", "boottime文件删除失败", "路径:" .. file_path)
+        return
+    end
+
+    -- 13. 删除目录
+    if io.rmdir(dir_path) then
+        log.info("io.rmdir", "目录删除成功", "路径:" .. dir_path)
+        if not io.dexist(dir_path) then
+            log.info("验证结果", "目录删除验证成功")
+        else
+            log.error("验证结果", "目录删除验证失败")
+        end
+    else
+        log.error("io.rmdir", "目录删除失败", "路径:" .. dir_path)
+        return
+    end
+
+    -- 再次获取文件系统信息,查看空间变化
+    local final_success, final_total_blocks, final_used_blocks, final_block_size, final_fs_type =  io.fsstat(base_path)
+    if final_success then
+        log.info(" io.fsstat", "操作后文件系统信息:", 
+                 "总空间=" .. final_total_blocks .. "块", 
+                 "已用=" .. final_used_blocks .. "块", 
+                 "块大小=" .. final_block_size.."字节",
+                 "类型=" .. final_fs_type)
+    end
+
+    log.info("文件系统操作", "===== 文件系统操作完成 =====")
+end
+
+sys.taskInit(flash_fs_io_task)

+ 85 - 0
module/Air8101/demo/fs_io/http_download_flash.lua

@@ -0,0 +1,85 @@
+--[[
+@module http_download_flash
+@summary HTTP下载文件到内置Flash模块
+@version 1.0.0
+@date    2025.09.23
+@author  王棚嶙
+@usage
+本文件演示的功能为通过HTTP下载文件到内置Flash中:
+1. 网络就绪检测
+2. 创建HTTP下载任务并等待完成
+3. 记录下载结果
+4. 获取并记录文件大小(使用io.fileSize)
+本文件没有对外接口,直接在main.lua中require "http_download_flash"即可
+]]
+
+local function http_download_flash_task()
+
+    
+    -- 要连接的WIFI路由器名称
+    local ssid ="A上海合宙通讯"
+    -- 要连接的WIFI路由器密码
+    local password = "HZ88888888"
+    log.info("wifi", ssid, password)
+    wlan.init()
+    -- 连接WIFI
+    wlan.connect(ssid, password, 1)
+
+    -- 阶段1: 网络就绪检测
+    while not socket.adapter(socket.dft()) do
+        log.warn("HTTP下载", "等待网络连接", socket.dft())
+        sys.waitUntil("IP_READY", 1000)
+    end
+
+    log.info("HTTP下载", "网络已就绪", socket.dft())
+
+    -- 阶段2: 执行下载任务
+    log.info("HTTP下载", "开始下载任务")
+
+    -- 创建下载目录
+    local download_dir = "/downloads"
+    if not io.dexist(download_dir) then
+        io.mkdir(download_dir)
+    end
+
+    -- 核心下载操作开始
+    local code, headers, body_size = http.request("GET",
+                                    "https://www.air32.cn/demo/sample-6s.mp3",
+                                    nil, nil, {dst = download_dir .. "/sample-6s.mp3"}).wait()
+
+    -- 阶段3: 记录下载结果
+    log.info("HTTP下载", "下载完成", 
+        code == 200 and "success" or "error", 
+        code, 
+        json.encode(headers or {}), 
+        body_size) 
+        
+    if code == 200 then
+        -- 获取实际文件大小 (使用io.fileSize接口)
+        local actual_size = io.fileSize(download_dir .. "/sample-6s.mp3")
+        if not actual_size then
+            -- 备用方案
+            actual_size = io.fileSize(download_dir .. "/sample-6s.mp3")
+        end
+        
+        log.info("HTTP下载", "文件大小验证", "预期:", body_size, "实际:", actual_size)
+        
+        if actual_size ~= body_size then
+            log.error("HTTP下载", "文件大小不一致", "预期:", body_size, "实际:", actual_size)
+        end
+        
+        -- 展示下载后的文件系统状态
+        local success, total_blocks, used_blocks, block_size, fs_type =  io.fsstat("/")
+        if success then
+            log.info("HTTP下载", "下载后文件系统信息:", 
+                     "总空间=" .. total_blocks .. "块", 
+                     "已用=" .. used_blocks .. "块", 
+                     "块大小=" .. block_size.."字节",
+                     "类型=" .. fs_type)
+        end
+    end
+
+end
+
+-- 创建下载任务
+sys.taskInit(http_download_flash_task)

+ 78 - 0
module/Air8101/demo/fs_io/main.lua

@@ -0,0 +1,78 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@version 001.000.000
+@date    2025.09.23
+@author  王棚嶙
+@usage
+本 Demo 演示了在Air8101内置Flash文件系统中的完整操作流程:
+1. 基础操作:看门狗守护机制
+2. 文件系统操作:
+   - 文件系统信息查询( io.fsstat)
+   - 文件大小获取(io.fileSize)
+   - 文件创建/读写/追加
+   - 目录创建/删除
+   - 文件重命名/删除
+   - 文件存在性检查
+3. 下载功能:
+   - 网络检测与HTTP文件下载到内置Flash
+]]
+
+--[[
+必须定义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 = "flash_fs_io_demo"
+VERSION = "001.000.000"
+
+-- 在日志中打印项目名和项目版本号
+log.info("main", PROJECT, VERSION)
+
+-- 添加硬狗防止程序卡死
+if wdt then
+    -- 初始化watchdog设置为9s
+    wdt.init(9000)
+    -- 3s喂一次狗 
+    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)
+
+--[[在加载以下两个功能时,建议分别打开进行测试,因为文件操作和http下载功能是异步操作。放到一个项目中,如果加载的时间点是随机的,就会出现哪个任务先抢到CPU时间片,哪个就先执行,不符合正常的业务逻辑,用户在参考编程的时候也要注意。]]
+
+-- 加载内置Flash文件系统操作演示模块
+require "flash_fs_io"
+-- 加载HTTP下载存入内置Flash功能演示模块
+-- require "http_download_flash"
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+-- sys.run()之后后面不要加任何语句!!!!!
+sys.run()

+ 143 - 0
module/Air8101/demo/fs_io/readme.md

@@ -0,0 +1,143 @@
+## **功能模块介绍**
+
+本 Demo 演示了在Air8101内置Flash文件系统中的完整操作流程,覆盖了从文件系统读写到高级文件操作的完整功能链。项目分为两个核心模块:
+
+1、main.lua:主程序入口 <br> 
+2、flash_fs_io.lua:内置Flash文件系统的操作测试流程模块,实现文件系统管理、文件操作和目录管理功能。<br> 
+3、http_download_flash.lua:HTTP下载模块,演示HTTP下载文件到内置Flash中的功能
+
+## **演示功能概述**
+
+### 1、主程序入口模块(main.lua)
+
+- 初始化项目信息和版本号
+- 初始化看门狗,并定时喂狗
+- 启动一个循环定时器,每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况方便分析内存使用是否有异常
+- 加载flash_fs_io模块(通过require "flash_fs_io")
+- 加载http_download_flash模块(通过require "http_download_flash")
+- 最后运行sys.run()。
+
+### 2、内置Flash文件系统演示模块(flash_fs_io.lua)
+
+#### 文件操作
+- 获取文件系统信息( io.fsstat)
+- 创建目录:io.mkdir("/flash_demo")
+- 创建/写入文件: io.open("/flash_demo/boottime", "wb")
+- 检查文件存在: io.exists(file_path)
+- 获取文件大小:io.fileSize(file_path)
+- 读取文件内容: io.open(file_path, "rb"):read("*a")
+- 启动计数文件: 记录设备启动次数
+- 文件追加: io.open(append_file, "a+")
+- 按行读取: file:read("*l")
+- 文件关闭: file:close()
+- 文件重命名: os.rename(old_path, new_path)
+- 列举目录: io.lsdir(dir_path)
+- 删除文件: os.remove(file_path)
+- 删除目录: io.rmdir(dir_path)
+
+### 3、HTTP下载功能 (http_download_flash.lua)
+
+
+#### 网络就绪检测
+
+- 连接WiFi
+- 1秒循环等待IP就绪
+- 网络故障处理机制
+
+#### 安全下载
+
+- HTTP下载
+
+#### 结果处理
+
+- 下载状态码解析
+- 自动文件大小验证
+- 获取文件系统信息( io.fsstat)
+
+## **演示硬件环境**
+
+1、Air8101核心板一块
+
+2、TYPE-C USB数据线一根
+
+3、Air8101核心板和数据线的硬件接线方式为
+
+- Air8101核心板通过TYPE-C USB口供电;(正面的开关拨到3.3v,背面的开关拨到off)
+
+- TYPE-C USB数据线直接插到Air8101核心板的TYPE-C USB座子,另外一端连接电脑USB口
+
+## **演示软件环境**
+
+1、Luatools下载调试工具:https://docs.openluat.com/air780epm/common/Luatools/
+
+2、内核固件版本:https://docs.openluat.com/air8101/luatos/firmware/
+
+## **演示核心步骤**
+
+1、搭建好硬件环境
+
+2、通过Luatools将demo与固件烧录到开发板中
+
+3、烧录好后,板子开机将会在Luatools上看到如下打印
+
+```lua
+
+(1)文件操作演示
+[2025-10-22 16:32:47.705] luat:U(172):I/user.文件系统操作 ===== 开始文件系统操作 =====
+[2025-10-22 16:32:47.705] luat:U(174):I/user. io.fsstat成功: 总空间=64块 已用=2块 块大小=4096字节 类型=lfs
+[2025-10-22 16:32:47.767] luat:U(215):I/user.io.mkdir 目录创建成功 路径:/flash_demo
+[2025-10-22 16:32:47.767] luat:U(224):I/user.文件创建 文件写入成功 路径:/flash_demo/boottime
+[2025-10-22 16:32:47.767] luat:U(226):I/user.io.exists 文件存在 路径:/flash_demo/boottime
+[2025-10-22 16:32:47.767] luat:U(228):I/user.io.fileSize 文件大小:59字节 路径:/flash_demo/boottime
+[2025-10-22 16:32:47.767] luat:U(230):I/user.文件读取 路径:/flash_demo/boottime 内容:这是内置Flash文件系统API文档示例的测试内容
+[2025-10-22 16:32:47.767] luat:U(232):I/user.启动计数 文件内容: 这是内置Flash文件系统API文档示例的测试内容 十六进制: E8BF99E698AFE58685E7BDAE466C617368E69687E4BBB6E7B3BBE7BB9F415049E69687E6A1A3E7A4BAE4BE8BE79A84E6B58BE8AF95E58685E5AEB9 118
+[2025-10-22 16:32:47.767] luat:U(233):I/user.启动计数 当前值: 0
+[2025-10-22 16:32:47.767] luat:U(233):I/user.启动计数 更新值: 1
+[2025-10-22 16:32:47.767] luat:U(238):I/user.文件写入 路径:/flash_demo/boottime 内容: 1
+[2025-10-22 16:32:47.831] luat:U(249):I/user.文件创建 路径:/flash_demo/test_a 初始内容:ABC
+[2025-10-22 16:32:47.831] luat:U(255):I/user.文件追加 路径:/flash_demo/test_a 追加内容:def
+[2025-10-22 16:32:47.831] luat:U(257):I/user.文件验证 路径:/flash_demo/test_a 内容:ABCdef 结果: 成功
+[2025-10-22 16:32:47.831] luat:U(266):I/user.文件创建 路径:/flash_demo/testline 写入3行文本
+[2025-10-22 16:32:47.831] luat:U(268):I/user.按行读取 路径:/flash_demo/testline 第1行: abc
+[2025-10-22 16:32:47.831] luat:U(269):I/user.按行读取 路径:/flash_demo/testline 第2行: 123
+[2025-10-22 16:32:47.831] luat:U(269):I/user.按行读取 路径:/flash_demo/testline 第3行: wendal
+[2025-10-22 16:32:47.831] luat:U(277):I/user.os.rename 文件重命名成功 原路径:/flash_demo/test_a 新路径:/flash_demo/renamed_file.txt
+[2025-10-22 16:32:47.831] luat:D(281):vfs:fopen /flash_demo/test_a r not found
+[2025-10-22 16:32:47.831] luat:U(281):I/user.验证结果 重命名验证成功 新文件存在 原文件不存在
+[2025-10-22 16:32:47.831] luat:U(282):I/user.目录操作 ===== 开始目录列举 =====
+[2025-10-22 16:32:47.831] luat:U(291):I/user.fs lsdir [{"name":"boottime","size":1,"type":0},{"name":"renamed_file.txt","size":6,"type":0},{"name":"testline","size":15,"type":0}]
+[2025-10-22 16:32:47.831] luat:U(297):I/user.os.remove 文件删除成功 路径:/flash_demo/renamed_file.txt
+[2025-10-22 16:32:47.831] luat:D(299):vfs:fopen /flash_demo/renamed_file.txt r not found
+[2025-10-22 16:32:47.831] luat:U(299):I/user.验证结果 renamed_file.txt文件删除验证成功
+[2025-10-22 16:32:47.831] luat:U(305):I/user.os.remove testline文件删除成功 路径:/flash_demo/testline
+[2025-10-22 16:32:47.831] luat:D(307):vfs:fopen /flash_demo/testline r not found
+[2025-10-22 16:32:47.831] luat:U(307):I/user.验证结果 testline文件删除验证成功
+[2025-10-22 16:32:47.831] luat:U(313):I/user.os.remove 文件删除成功 路径:/flash_demo/boottime
+[2025-10-22 16:32:47.831] luat:D(315):vfs:fopen /flash_demo/boottime r not found
+[2025-10-22 16:32:47.831] luat:U(316):I/user.验证结果 boottime文件删除验证成功
+[2025-10-22 16:32:47.988] luat:U(326):I/user.io.rmdir 目录删除成功 路径:/flash_demo
+[2025-10-22 16:32:47.988] luat:U(327):I/user.验证结果 目录删除验证成功
+[2025-10-22 16:32:47.988] luat:U(329):I/user. io.fsstat 操作后文件系统信息: 总空间=64块 已用=2块 块大小=4096字节 类型=lfs
+[2025-10-22 16:32:47.988] luat:U(330):I/user.文件系统操作 ===== 文件系统操作完成 =====
+
+
+
+
+
+(2)网络连接与HTTP下载
+[2025-10-24 10:51:10.116] luat:U(2895):I/user.HTTP下载 网络已就绪 2 2
+[2025-10-24 10:51:10.116] luat:U(2896):I/user.HTTP下载 开始下载任务
+[2025-10-24 10:51:10.202] luat:D(2967):DNS:www.air32.cn state 0 id 1 ipv6 0 use dns server0, try 0
+[2025-10-24 10:51:10.202] luat:D(2967):net:adatper 2 dns server 192.168.1.1
+[2025-10-24 10:51:10.202] luat:D(2968):net:dns udp sendto 192.168.1.1:53 from 192.168.1.116
+[2025-10-24 10:51:10.202] luat:D(2971):wlan:sta ip 192.168.1.116
+[2025-10-24 10:51:10.202] luat:D(2971):wlan:设置STA网卡可用
+[2025-10-24 10:51:10.222] luat:I(2989):DNS:dns all done ,now stop
+[2025-10-24 10:51:10.222] luat:D(2990):net:adapter 2 connect 49.232.89.122:443 TCP
+[2025-10-24 10:51:14.599] luat:U(7368):I/user.HTTP下载 下载完成 success 200 {"Last-Modified":"Thu, 23 Oct 2025 03:14:41 GMT","Accept-Ranges":"bytes","ETag":"\"68f99da1-1929e\"","Date":"Fri, 24 Oct 2025 02:51:09 GMT","Connection":"keep-alive","Server":"openresty\/1.27.1.2","Content-Length":"103070","Content-Type":"audio\/mpeg"} 103070
+[2025-10-24 10:51:14.599] luat:U(7384):I/user.HTTP下载 文件大小验证 预期: 103070 实际: 103070
+[2025-10-24 10:51:14.630] luat:U(7409):I/user.HTTP下载 下载后文件系统信息: 总空间=64块 已用=30块 块大小=4096字节 类型=lfs
+
+
+
+```