Przeglądaj źródła

update:更新主流模组的 protobuf 示例代码为最新版本

mengyang 3 miesięcy temu
rodzic
commit
b38acd8e9e

+ 66 - 62
module/Air780EHM_Air780EHV_Air780EGH/demo/protobuf/main.lua

@@ -1,71 +1,75 @@
---- 模块功能:Google ProtoBuffs 编解码
--- @module pb
--- @author wendal
--- @release 2022.9.8
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@version 1.0
+@date    2025.11.05
+@author  马梦阳
+@usage
 
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "pbdemo"
-VERSION = "1.0.1"
+本demo演示的核心功能为:
+1.protobuf 的编码与解码;
 
+更多说明参考本目录下的 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 = "protobuf"
+VERSION = "001.000.000"
+
+
+-- 在日志中打印项目名和项目版本号
 log.info("main", PROJECT, VERSION)
 
--- sys库是标配
-_G.sys = require("sys")
 
---添加硬狗防止程序卡死
+-- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
+-- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
 if wdt then
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+    --配置喂狗超时时间为9秒钟
+    wdt.init(9000)
+    --启动一个循环定时器,每隔3秒钟喂一次狗
+    sys.timerLoopStart(wdt.feed, 3000)
 end
 
-sys.taskInit(function()
-    sys.wait(500)
-    if not protobuf then
-        log.info("protobuf", "this demo need protobuf lib")
-        return
-    end
-    -- 加载 pb 文件, 这个是从pbtxt 转换得到的
-    -- 下载资源到模块时不需要下载pbtxt
-    -- 转换命令: protoc.exe -operson.pb person.pbtxt
-    -- protoc.exe 下载地址: https://github.com/protocolbuffers/protobuf/releases
-    local pb_file = "/luadb/person.pb"
-    
-    if io.exists(pb_file) then
-        protobuf.load(io.readFile(pb_file))
-        sys.publish("pb_file_exists")
-    else
-        log.info("protobuf","Failed to load file")
-    end
-
-    local tb = {
-        name = "wendal",
-        id = 123,
-        email = "abc@qq.com"
-    }
-    while 1 do
-        sys.waitUntil("pb_file_exists")
-        sys.wait(1000)
-        -- 用 protobuf 编码数据
-        local pbdata = protobuf.encode("Person", tb)
-        if pbdata then
-            -- 打印数据长度. 编码后的数据含不可见字符, toHex是方便显示
-            log.info("protobuf", "encode",  #pbdata, (pbdata:toHex()))
-        end
-        -- 用 json 编码数据, 用于对比大小
-        local jdata = json.encode(tb)
-        if jdata then
-            log.info("json", #jdata, jdata)
-        end
-        -- 可见 protobuffs 比 json 节省很多空间
-
-        -- 后续是演示解码
-        local re = protobuf.decode("Person", pbdata)
-        if re then
-            -- 打印数据, 因为table不能直接显示, 这里转成json来显示
-            log.info("protobuf", "decode", json.encode(re))
-        end
-    end
-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)
+
+
+-- 加载 protobuf 应用模块
+require "protobuf_app"
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
 sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 3 - 6
module/Air780EHM_Air780EHV_Air780EGH/demo/protobuf/person.pbtxt

@@ -1,6 +1,3 @@
-syntax = "proto2";
-message Person {
-  optional string name = 1;
-  optional int32 id = 2;
-  optional string email = 3;
-}
+name: "wendal"
+id: 123
+email: "abc@qq.com"

+ 6 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/protobuf/person.proto

@@ -0,0 +1,6 @@
+syntax = "proto2";
+message Person {
+  optional string name = 1;
+  optional int32 id = 2;
+  optional string email = 3;
+}

+ 83 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/protobuf/protobuf_app.lua

@@ -0,0 +1,83 @@
+--[[
+@module  protobuf_app
+@summary protobuf 编解码功能模块
+@version 1.0
+@date    2025.11.05
+@author  马梦阳
+@usage
+本功能模块演示的内容为:
+1.加载 protobuf 定义文件;
+2.将符合 protobuf 定义的 Lua table 数据编码为二进制数据;
+3.使用 json 编码同样的 Lua table 数据后,对比 protobuf 和 json 编码后数据的大小;
+4.将二进制数据解码为 Lua table 数据;
+5.清除所有已加载的定义数据;
+
+
+本文件没有对外接口,直接在 main.lua 中 require "protobuf_app" 就可以加载运行;
+]]
+
+
+local function main_task()
+    -- 加载 pb 文件, 这个是 proto 经过 protoc.exe 编译后生成的二进制文件
+    -- 下载资源到模块时不需要下载 proto 文件
+    -- 转换命令: protoc -o person.pb person.proto
+    -- protoc.exe 下载地址: https://github.com/protocolbuffers/protobuf/releases
+    local pb_file = "/luadb/person.pb"
+
+    local tbdata = {
+        name = "wendal",
+        id = 123,
+        email = "abc@qq.com"
+    }
+
+    if io.exists(pb_file) then
+        local success, bytesRead = protobuf.load(io.readFile(pb_file))
+        if not success then
+            log.info("protobuf", "加载 protobuf 定义失败,已读取 " .. bytesRead .. " 字节")
+            return
+        else
+            log.info("protobuf", "加载 protobuf 定义成功,共解析 " .. bytesRead .. " 字节")
+        end
+    else
+        log.info("protobuf", "pb 文件不存在")
+        return
+    end
+
+    -- 编码数据;
+    local pbdata = protobuf.encode("Person", tbdata)
+    if pbdata then
+        -- 编码成功,编码后的数据通常包含不可见字符;
+        -- 打印长度和十六进制内容(便于调试);
+        log.info("protobuf", "编码成功,数据长度:" .. #pbdata)
+        log.info("protobuf", "十六进制内容:" .. pbdata:toHex())
+    else
+        log.info("protobuf", "编码失败:数据格式或类型不匹配")
+    end
+
+    -- 对比 protobuf 编码和 json 编码的大小;
+    local jdata = json.encode(tbdata)
+    if jdata then
+        log.info("json", "编码成功,数据长度:" .. #jdata)
+        log.info("json", "数据内容:" .. jdata)
+    else
+        log.info("json", "编码失败:数据格式或类型不匹配")
+    end
+    -- 可见 protobuffs 比 json 节省很多空间;
+
+    -- 数据解码;
+    local tbdata = protobuf.decode("Person", pbdata)
+    if tbdata then
+        -- 解码后的数据为 Lua table 格式,需要转化为 json 进行显示;
+        log.info("protobuf", "解码成功,数据内容:", json.encode(tbdata))
+    else
+        log.info("protobuf", "解码失败")
+    end
+
+    -- 清除所有已加载的定义数据;
+    protobuf.clear()
+    log.info("protobuf", "所有 protobuf 定义已清除")
+end
+
+-- 创建并启动一个 task
+-- 用于运行 main_task 函数
+sys.taskInit(main_task)

+ 102 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/protobuf/readme.md

@@ -0,0 +1,102 @@
+## 演示模块概述
+
+1、main.lua:主程序入口;
+
+2、protobuf_app.lua:protobuf 编解码功能模块;
+
+## 演示功能概述
+
+使用 Air780EHM/EHV/EGH 核心板搭配 protobuf 库演示 protobuf 编码与解码功能;
+
+1、加载 protobuf 定义文件;
+
+2、将符合 protobuf 定义的 Lua table 数据编码为二进制数据;
+
+3、使用 json 编码同样的 Lua table 数据后,对比 protobuf 和 json 编码后数据的大小;
+
+4、将二进制数据解码为 Lua table 数据;
+
+5、清除所有已加载的定义数据;
+
+注意事项:
+
+1、protobuf 库支持 Proto2 和 Proto3 协议版本;
+
+2、person.proto 文件是消息结构定义文件(Schema),它是人类可读的文本文件,使用 Protobuf IDL 语法,该文件定义了消息类型 Person 的结构(字段名、类型、编号等),文件中示例内容如下:
+
+```protobuf
+syntax = "proto2";
+
+message Person {
+  optional string name = 1;
+  optional int32 id = 2;
+  optional string email = 3;
+}
+```
+
+该文件需要由开发者手动创建编写,语言规范参考:
+
+Protocol Buffers 官方语言指南(proto3):[Language Guide (proto 3) | Protocol Buffers Documentation](https://protobuf.dev/programming-guides/proto3/) ;
+
+Protocol Buffers 官方语言指南(proto2):[Language Guide (proto 2) | Protocol Buffers Documentation](https://protobuf.dev/programming-guides/proto2/) ;
+
+3、person.pb 文件是 Schema 描述的二进制文件(FileDescriptorSet),是 person.proto 经过 protoc -o 编译后生成的二进制元数据,该文件包含 Person 消息的完整结构描述(字段名、编号、类型),用于被 protobuf.load() 加载,供后续 protobuf.encode() 和 protobuf.decode() 能知道 Person 的结构,从而正确编解码;
+
+4、关于如何得到 person.pb 文件说明如下:
+
+- 需要先下载 protoc.exe,下载链接:https://github.com/protocolbuffers/protobuf/releases ;
+- 在 protoc.exe 文件目录下打开 CMD,输入 protoc -o person.pb person.proto 即可生成 person.pb 文件,前提需要同目录下包含 person.proto 文件;
+
+5、person.pbtxt 文件是用户数据的文本表示(TextFormat),它是人类可读的文本文件,表示一个具体的 Person 消息实例,内容是字段赋值,文件中示例内容如下:
+
+```textproto
+name: "wendal"
+id: 123
+email: "abc@qq.com"
+```
+
+该文件需要用户手动编写(用于配置、测试),或者通过程序把用户数据以人类可读的文本格式保存在 .pbtxt 文件下;
+
+该文件内容需要遵循 Protobuf 文本格式语法规范(Text Format Syntax),语言规范参考:
+
+Protobuf Text Format 官方语言规范(草案):[Text Format Language Specification | Protocol Buffers Documentation](https://protobuf.dev/reference/protobuf/textformat-spec/) ;
+
+6、person.pbtxt 文件用于调试、写测试用例、作为配置文件,可被支持 TextFormat 的 Protobuf 库解析为内存对象,在 LuatOS 中不使用 .pbtxt 文件(protobuf 库只支持 binary encode/decode,也就是 .pb 文件);
+
+## 演示硬件环境
+
+1、Air780EHM/EHV/EGH 核心板一块
+
+2、TYPE-C USB数据线一根
+
+## 演示软件环境
+
+1、[Luatools下载调试工具](https://docs.openluat.com/air8000/luatos/common/download/)
+
+2、[Air780EHM V2016 版本](https://docs.openluat.com/air780epm/luatos/firmware/version/)(理论上最新版本固件也可以,如果使用最新版本的固件不可以,可以烧录 V2016-1 固件对比验证)
+
+3、[Air780EHV V2016 版本](https://docs.openluat.com/air780ehv/luatos/firmware/version/)(理论上最新版本固件也可以,如果使用最新版本的固件不可以,可以烧录 V2016-1 固件对比验证)
+
+4、[Air780EGH V2016 版本](https://docs.openluat.com/air780egh/luatos/firmware/version/)(理论上最新版本固件也可以,如果使用最新版本的固件不可以,可以烧录 V2016-1 固件对比验证)
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、Luatools 工具烧录内核固件和 demo 脚本代码
+
+3、烧录成功后,自动开机运行
+
+4、正常运行情况时的日志如下:
+
+```
+[000000000.744] I/user.main protobuf 001.000.000
+[000000000.753] I/user.protobuf 加载 protobuf 定义成功,共解析 85 字节
+[000000000.753] I/user.protobuf 编码成功,数据长度:22
+[000000000.754] I/user.protobuf 十六进制内容:0A0677656E64616C107B1A0A6162634071712E636F6D
+[000000000.754] I/user.json 编码成功,数据长度:47
+[000000000.754] I/user.json 数据内容:{"name":"wendal","id":123,"email":"abc@qq.com"}
+[000000000.755] I/user.protobuf 解码成功,数据内容: {"name":"wendal","id":123,"email":"abc@qq.com"}
+[000000000.755] I/user.protobuf 所有 protobuf 定义已清除
+```
+

+ 66 - 62
module/Air780EPM/demo/protobuf/main.lua

@@ -1,71 +1,75 @@
---- 模块功能:Google ProtoBuffs 编解码
--- @module pb
--- @author wendal
--- @release 2022.9.8
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@version 1.0
+@date    2025.11.05
+@author  马梦阳
+@usage
 
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "pbdemo"
-VERSION = "1.0.1"
+本demo演示的核心功能为:
+1.protobuf 的编码与解码;
 
+更多说明参考本目录下的 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 = "protobuf"
+VERSION = "001.000.000"
+
+
+-- 在日志中打印项目名和项目版本号
 log.info("main", PROJECT, VERSION)
 
--- sys库是标配
-_G.sys = require("sys")
 
---添加硬狗防止程序卡死
+-- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
+-- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
 if wdt then
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+    --配置喂狗超时时间为9秒钟
+    wdt.init(9000)
+    --启动一个循环定时器,每隔3秒钟喂一次狗
+    sys.timerLoopStart(wdt.feed, 3000)
 end
 
-sys.taskInit(function()
-    sys.wait(500)
-    if not protobuf then
-        log.info("protobuf", "this demo need protobuf lib")
-        return
-    end
-    -- 加载 pb 文件, 这个是从pbtxt 转换得到的
-    -- 下载资源到模块时不需要下载pbtxt
-    -- 转换命令: protoc.exe -operson.pb person.pbtxt
-    -- protoc.exe 下载地址: https://github.com/protocolbuffers/protobuf/releases
-    local pb_file = "/luadb/person.pb"
-    
-    if io.exists(pb_file) then
-        protobuf.load(io.readFile(pb_file))
-        sys.publish("pb_file_exists")
-    else
-        log.info("protobuf","Failed to load file")
-    end
-
-    local tb = {
-        name = "wendal",
-        id = 123,
-        email = "abc@qq.com"
-    }
-    while 1 do
-        sys.waitUntil("pb_file_exists")
-        sys.wait(1000)
-        -- 用 protobuf 编码数据
-        local pbdata = protobuf.encode("Person", tb)
-        if pbdata then
-            -- 打印数据长度. 编码后的数据含不可见字符, toHex是方便显示
-            log.info("protobuf", "encode",  #pbdata, (pbdata:toHex()))
-        end
-        -- 用 json 编码数据, 用于对比大小
-        local jdata = json.encode(tb)
-        if jdata then
-            log.info("json", #jdata, jdata)
-        end
-        -- 可见 protobuffs 比 json 节省很多空间
-
-        -- 后续是演示解码
-        local re = protobuf.decode("Person", pbdata)
-        if re then
-            -- 打印数据, 因为table不能直接显示, 这里转成json来显示
-            log.info("protobuf", "decode", json.encode(re))
-        end
-    end
-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)
+
+
+-- 加载 protobuf 应用模块
+require "protobuf_app"
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
 sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 3 - 6
module/Air780EPM/demo/protobuf/person.pbtxt

@@ -1,6 +1,3 @@
-syntax = "proto2";
-message Person {
-  optional string name = 1;
-  optional int32 id = 2;
-  optional string email = 3;
-}
+name: "wendal"
+id: 123
+email: "abc@qq.com"

+ 6 - 0
module/Air780EPM/demo/protobuf/person.proto

@@ -0,0 +1,6 @@
+syntax = "proto2";
+message Person {
+  optional string name = 1;
+  optional int32 id = 2;
+  optional string email = 3;
+}

+ 83 - 0
module/Air780EPM/demo/protobuf/protobuf_app.lua

@@ -0,0 +1,83 @@
+--[[
+@module  protobuf_app
+@summary protobuf 编解码功能模块
+@version 1.0
+@date    2025.11.05
+@author  马梦阳
+@usage
+本功能模块演示的内容为:
+1.加载 protobuf 定义文件;
+2.将符合 protobuf 定义的 Lua table 数据编码为二进制数据;
+3.使用 json 编码同样的 Lua table 数据后,对比 protobuf 和 json 编码后数据的大小;
+4.将二进制数据解码为 Lua table 数据;
+5.清除所有已加载的定义数据;
+
+
+本文件没有对外接口,直接在 main.lua 中 require "protobuf_app" 就可以加载运行;
+]]
+
+
+local function main_task()
+    -- 加载 pb 文件, 这个是 proto 经过 protoc.exe 编译后生成的二进制文件
+    -- 下载资源到模块时不需要下载 proto 文件
+    -- 转换命令: protoc -o person.pb person.proto
+    -- protoc.exe 下载地址: https://github.com/protocolbuffers/protobuf/releases
+    local pb_file = "/luadb/person.pb"
+
+    local tbdata = {
+        name = "wendal",
+        id = 123,
+        email = "abc@qq.com"
+    }
+
+    if io.exists(pb_file) then
+        local success, bytesRead = protobuf.load(io.readFile(pb_file))
+        if not success then
+            log.info("protobuf", "加载 protobuf 定义失败,已读取 " .. bytesRead .. " 字节")
+            return
+        else
+            log.info("protobuf", "加载 protobuf 定义成功,共解析 " .. bytesRead .. " 字节")
+        end
+    else
+        log.info("protobuf", "pb 文件不存在")
+        return
+    end
+
+    -- 编码数据;
+    local pbdata = protobuf.encode("Person", tbdata)
+    if pbdata then
+        -- 编码成功,编码后的数据通常包含不可见字符;
+        -- 打印长度和十六进制内容(便于调试);
+        log.info("protobuf", "编码成功,数据长度:" .. #pbdata)
+        log.info("protobuf", "十六进制内容:" .. pbdata:toHex())
+    else
+        log.info("protobuf", "编码失败:数据格式或类型不匹配")
+    end
+
+    -- 对比 protobuf 编码和 json 编码的大小;
+    local jdata = json.encode(tbdata)
+    if jdata then
+        log.info("json", "编码成功,数据长度:" .. #jdata)
+        log.info("json", "数据内容:" .. jdata)
+    else
+        log.info("json", "编码失败:数据格式或类型不匹配")
+    end
+    -- 可见 protobuffs 比 json 节省很多空间;
+
+    -- 数据解码;
+    local tbdata = protobuf.decode("Person", pbdata)
+    if tbdata then
+        -- 解码后的数据为 Lua table 格式,需要转化为 json 进行显示;
+        log.info("protobuf", "解码成功,数据内容:", json.encode(tbdata))
+    else
+        log.info("protobuf", "解码失败")
+    end
+
+    -- 清除所有已加载的定义数据;
+    protobuf.clear()
+    log.info("protobuf", "所有 protobuf 定义已清除")
+end
+
+-- 创建并启动一个 task
+-- 用于运行 main_task 函数
+sys.taskInit(main_task)

+ 98 - 0
module/Air780EPM/demo/protobuf/readme.md

@@ -0,0 +1,98 @@
+## 演示模块概述
+
+1、main.lua:主程序入口;
+
+2、protobuf_app.lua:protobuf 编解码功能模块;
+
+## 演示功能概述
+
+使用 Air780EPM 核心板搭配 protobuf 库演示 protobuf 编码与解码功能;
+
+1、加载 protobuf 定义文件;
+
+2、将符合 protobuf 定义的 Lua table 数据编码为二进制数据;
+
+3、使用 json 编码同样的 Lua table 数据后,对比 protobuf 和 json 编码后数据的大小;
+
+4、将二进制数据解码为 Lua table 数据;
+
+5、清除所有已加载的定义数据;
+
+注意事项:
+
+1、protobuf 库支持 Proto2 和 Proto3 协议版本;
+
+2、person.proto 文件是消息结构定义文件(Schema),它是人类可读的文本文件,使用 Protobuf IDL 语法,该文件定义了消息类型 Person 的结构(字段名、类型、编号等),文件中示例内容如下:
+
+```protobuf
+syntax = "proto2";
+
+message Person {
+  optional string name = 1;
+  optional int32 id = 2;
+  optional string email = 3;
+}
+```
+
+该文件需要由开发者手动创建编写,语言规范参考:
+
+Protocol Buffers 官方语言指南(proto3):[Language Guide (proto 3) | Protocol Buffers Documentation](https://protobuf.dev/programming-guides/proto3/) ;
+
+Protocol Buffers 官方语言指南(proto2):[Language Guide (proto 2) | Protocol Buffers Documentation](https://protobuf.dev/programming-guides/proto2/) ;
+
+3、person.pb 文件是 Schema 描述的二进制文件(FileDescriptorSet),是 person.proto 经过 protoc -o 编译后生成的二进制元数据,该文件包含 Person 消息的完整结构描述(字段名、编号、类型),用于被 protobuf.load() 加载,供后续 protobuf.encode() 和 protobuf.decode() 能知道 Person 的结构,从而正确编解码;
+
+4、关于如何得到 person.pb 文件说明如下:
+
+- 需要先下载 protoc.exe,下载链接:https://github.com/protocolbuffers/protobuf/releases ;
+- 在 protoc.exe 文件目录下打开 CMD,输入 protoc -o person.pb person.proto 即可生成 person.pb 文件,前提需要同目录下包含 person.proto 文件;
+
+5、person.pbtxt 文件是用户数据的文本表示(TextFormat),它是人类可读的文本文件,表示一个具体的 Person 消息实例,内容是字段赋值,文件中示例内容如下:
+
+```textproto
+name: "wendal"
+id: 123
+email: "abc@qq.com"
+```
+
+该文件需要用户手动编写(用于配置、测试),或者通过程序把用户数据以人类可读的文本格式保存在 .pbtxt 文件下;
+
+该文件内容需要遵循 Protobuf 文本格式语法规范(Text Format Syntax),语言规范参考:
+
+Protobuf Text Format 官方语言规范(草案):[Text Format Language Specification | Protocol Buffers Documentation](https://protobuf.dev/reference/protobuf/textformat-spec/) ;
+
+6、person.pbtxt 文件用于调试、写测试用例、作为配置文件,可被支持 TextFormat 的 Protobuf 库解析为内存对象,在 LuatOS 中不使用 .pbtxt 文件(protobuf 库只支持 binary encode/decode,也就是 .pb 文件);
+
+## 演示硬件环境
+
+1、Air780EPM 核心板一块
+
+2、TYPE-C USB数据线一根
+
+## 演示软件环境
+
+1、[Luatools下载调试工具](https://docs.openluat.com/air8000/luatos/common/download/)
+
+2、[Air780EPM V2016 版本](https://docs.openluat.com/air780epm/luatos/firmware/version/)(理论上最新版本固件也可以,如果使用最新版本的固件不可以,可以烧录 V2016-1 固件对比验证)
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、Luatools 工具烧录内核固件和 demo 脚本代码
+
+3、烧录成功后,自动开机运行
+
+4、正常运行情况时的日志如下:
+
+```
+[000000000.744] I/user.main protobuf 001.000.000
+[000000000.753] I/user.protobuf 加载 protobuf 定义成功,共解析 85 字节
+[000000000.753] I/user.protobuf 编码成功,数据长度:22
+[000000000.754] I/user.protobuf 十六进制内容:0A0677656E64616C107B1A0A6162634071712E636F6D
+[000000000.754] I/user.json 编码成功,数据长度:47
+[000000000.754] I/user.json 数据内容:{"name":"wendal","id":123,"email":"abc@qq.com"}
+[000000000.755] I/user.protobuf 解码成功,数据内容: {"name":"wendal","id":123,"email":"abc@qq.com"}
+[000000000.755] I/user.protobuf 所有 protobuf 定义已清除
+```
+

+ 66 - 62
module/Air8000/demo/protobuf/main.lua

@@ -1,71 +1,75 @@
---- 模块功能:Google ProtoBuffs 编解码
--- @module pb
--- @author wendal
--- @release 2022.9.8
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@version 1.0
+@date    2025.10.31
+@author  马梦阳
+@usage
 
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "pbdemo"
-VERSION = "1.0.1"
+本demo演示的核心功能为:
+1.protobuf 的编码与解码;
 
+更多说明参考本目录下的 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 = "protobuf"
+VERSION = "001.000.000"
+
+
+-- 在日志中打印项目名和项目版本号
 log.info("main", PROJECT, VERSION)
 
--- sys库是标配
-_G.sys = require("sys")
 
---添加硬狗防止程序卡死
+-- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
+-- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
 if wdt then
-    wdt.init(9000)--初始化watchdog设置为9s
-    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+    --配置喂狗超时时间为9秒钟
+    wdt.init(9000)
+    --启动一个循环定时器,每隔3秒钟喂一次狗
+    sys.timerLoopStart(wdt.feed, 3000)
 end
 
-sys.taskInit(function()
-    sys.wait(500)
-    if not protobuf then
-        log.info("protobuf", "this demo need protobuf lib")
-        return
-    end
-    -- 加载 pb 文件, 这个是从pbtxt 转换得到的
-    -- 下载资源到模块时不需要下载pbtxt
-    -- 转换命令: protoc.exe -operson.pb person.pbtxt
-    -- protoc.exe 下载地址: https://github.com/protocolbuffers/protobuf/releases
-    local pb_file = "/luadb/person.pb"
-    
-    if io.exists(pb_file) then
-        protobuf.load(io.readFile(pb_file))
-        sys.publish("pb_file_exists")
-    else
-        log.info("protobuf","Failed to load file")
-    end
-
-    local tb = {
-        name = "wendal",
-        id = 123,
-        email = "abc@qq.com"
-    }
-    while 1 do
-        sys.waitUntil("pb_file_exists")
-        sys.wait(1000)
-        -- 用 protobuf 编码数据
-        local pbdata = protobuf.encode("Person", tb)
-        if pbdata then
-            -- 打印数据长度. 编码后的数据含不可见字符, toHex是方便显示
-            log.info("protobuf", "encode",  #pbdata, (pbdata:toHex()))
-        end
-        -- 用 json 编码数据, 用于对比大小
-        local jdata = json.encode(tb)
-        if jdata then
-            log.info("json", #jdata, jdata)
-        end
-        -- 可见 protobuffs 比 json 节省很多空间
-
-        -- 后续是演示解码
-        local re = protobuf.decode("Person", pbdata)
-        if re then
-            -- 打印数据, 因为table不能直接显示, 这里转成json来显示
-            log.info("protobuf", "decode", json.encode(re))
-        end
-    end
-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)
+
+
+-- 加载 protobuf 应用模块
+require "protobuf_app"
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
 sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 3 - 6
module/Air8000/demo/protobuf/person.pbtxt

@@ -1,6 +1,3 @@
-syntax = "proto2";
-message Person {
-  optional string name = 1;
-  optional int32 id = 2;
-  optional string email = 3;
-}
+name: "wendal"
+id: 123
+email: "abc@qq.com"

+ 6 - 0
module/Air8000/demo/protobuf/person.proto

@@ -0,0 +1,6 @@
+syntax = "proto2";
+message Person {
+  optional string name = 1;
+  optional int32 id = 2;
+  optional string email = 3;
+}

+ 83 - 0
module/Air8000/demo/protobuf/protobuf_app.lua

@@ -0,0 +1,83 @@
+--[[
+@module  protobuf_app
+@summary protobuf 编解码功能模块
+@version 1.0
+@date    2025.10.31
+@author  马梦阳
+@usage
+本功能模块演示的内容为:
+1.加载 protobuf 定义文件;
+2.将符合 protobuf 定义的 Lua table 数据编码为二进制数据;
+3.使用 json 编码同样的 Lua table 数据后,对比 protobuf 和 json 编码后数据的大小;
+4.将二进制数据解码为 Lua table 数据;
+5.清除所有已加载的定义数据;
+
+
+本文件没有对外接口,直接在 main.lua 中 require "protobuf_app" 就可以加载运行;
+]]
+
+
+local function main_task()
+    -- 加载 pb 文件, 这个是 proto 经过 protoc.exe 编译后生成的二进制文件
+    -- 下载资源到模块时不需要下载 proto 文件
+    -- 转换命令: protoc -o person.pb person.proto
+    -- protoc.exe 下载地址: https://github.com/protocolbuffers/protobuf/releases
+    local pb_file = "/luadb/person.pb"
+
+    local tbdata = {
+        name = "wendal",
+        id = 123,
+        email = "abc@qq.com"
+    }
+
+    if io.exists(pb_file) then
+        local success, bytesRead = protobuf.load(io.readFile(pb_file))
+        if not success then
+            log.info("protobuf", "加载 protobuf 定义失败,已读取 " .. bytesRead .. " 字节")
+            return
+        else
+            log.info("protobuf", "加载 protobuf 定义成功,共解析 " .. bytesRead .. " 字节")
+        end
+    else
+        log.info("protobuf", "pb 文件不存在")
+        return
+    end
+
+    -- 编码数据;
+    local pbdata = protobuf.encode("Person", tbdata)
+    if pbdata then
+        -- 编码成功,编码后的数据通常包含不可见字符;
+        -- 打印长度和十六进制内容(便于调试);
+        log.info("protobuf", "编码成功,数据长度:" .. #pbdata)
+        log.info("protobuf", "十六进制内容:" .. pbdata:toHex())
+    else
+        log.info("protobuf", "编码失败:数据格式或类型不匹配")
+    end
+
+    -- 对比 protobuf 编码和 json 编码的大小;
+    local jdata = json.encode(tbdata)
+    if jdata then
+        log.info("json", "编码成功,数据长度:" .. #jdata)
+        log.info("json", "数据内容:" .. jdata)
+    else
+        log.info("json", "编码失败:数据格式或类型不匹配")
+    end
+    -- 可见 protobuffs 比 json 节省很多空间;
+
+    -- 数据解码;
+    local tbdata = protobuf.decode("Person", pbdata)
+    if tbdata then
+        -- 解码后的数据为 Lua table 格式,需要转化为 json 进行显示;
+        log.info("protobuf", "解码成功,数据内容:", json.encode(tbdata))
+    else
+        log.info("protobuf", "解码失败")
+    end
+
+    -- 清除所有已加载的定义数据;
+    protobuf.clear()
+    log.info("protobuf", "所有 protobuf 定义已清除")
+end
+
+-- 创建并启动一个 task
+-- 用于运行 main_task 函数
+sys.taskInit(main_task)

+ 98 - 0
module/Air8000/demo/protobuf/readme.md

@@ -0,0 +1,98 @@
+## 演示模块概述
+
+1、main.lua:主程序入口;
+
+2、protobuf_app.lua:protobuf 编解码功能模块;
+
+## 演示功能概述
+
+使用 Air8000 核心板搭配 protobuf 库演示 protobuf 编码与解码功能;
+
+1、加载 protobuf 定义文件;
+
+2、将符合 protobuf 定义的 Lua table 数据编码为二进制数据;
+
+3、使用 json 编码同样的 Lua table 数据后,对比 protobuf 和 json 编码后数据的大小;
+
+4、将二进制数据解码为 Lua table 数据;
+
+5、清除所有已加载的定义数据;
+
+注意事项:
+
+1、protobuf 库支持 Proto2 和 Proto3 协议版本;
+
+2、person.proto 文件是消息结构定义文件(Schema),它是人类可读的文本文件,使用 Protobuf IDL 语法,该文件定义了消息类型 Person 的结构(字段名、类型、编号等),文件中示例内容如下:
+
+```protobuf
+syntax = "proto2";
+
+message Person {
+  optional string name = 1;
+  optional int32 id = 2;
+  optional string email = 3;
+}
+```
+
+该文件需要由开发者手动创建编写,语言规范参考:
+
+Protocol Buffers 官方语言指南(proto3):[Language Guide (proto 3) | Protocol Buffers Documentation](https://protobuf.dev/programming-guides/proto3/) ;
+
+Protocol Buffers 官方语言指南(proto2):[Language Guide (proto 2) | Protocol Buffers Documentation](https://protobuf.dev/programming-guides/proto2/) ;
+
+3、person.pb 文件是 Schema 描述的二进制文件(FileDescriptorSet),是 person.proto 经过 protoc -o 编译后生成的二进制元数据,该文件包含 Person 消息的完整结构描述(字段名、编号、类型),用于被 protobuf.load() 加载,供后续 protobuf.encode() 和 protobuf.decode() 能知道 Person 的结构,从而正确编解码;
+
+4、关于如何得到 person.pb 文件说明如下:
+
+- 需要先下载 protoc.exe,下载链接:https://github.com/protocolbuffers/protobuf/releases ;
+- 在 protoc.exe 文件目录下打开 CMD,输入 protoc -o person.pb person.proto 即可生成 person.pb 文件,前提需要同目录下包含 person.proto 文件;
+
+5、person.pbtxt 文件是用户数据的文本表示(TextFormat),它是人类可读的文本文件,表示一个具体的 Person 消息实例,内容是字段赋值,文件中示例内容如下:
+
+```textproto
+name: "wendal"
+id: 123
+email: "abc@qq.com"
+```
+
+该文件需要用户手动编写(用于配置、测试),或者通过程序把用户数据以人类可读的文本格式保存在 .pbtxt 文件下;
+
+该文件内容需要遵循 Protobuf 文本格式语法规范(Text Format Syntax),语言规范参考:
+
+Protobuf Text Format 官方语言规范(草案):[Text Format Language Specification | Protocol Buffers Documentation](https://protobuf.dev/reference/protobuf/textformat-spec/) ;
+
+6、person.pbtxt 文件用于调试、写测试用例、作为配置文件,可被支持 TextFormat 的 Protobuf 库解析为内存对象,在 LuatOS 中不使用 .pbtxt 文件(protobuf 库只支持 binary encode/decode,也就是 .pb 文件);
+
+## 演示硬件环境
+
+1、Air8000 核心板一块
+
+2、TYPE-C USB数据线一根
+
+## 演示软件环境
+
+1、[Luatools下载调试工具](https://docs.openluat.com/air8000/luatos/common/download/)
+
+2、[Air8000 V2016 版本](https://docs.openluat.com/air8000/luatos/common/download/)(理论上最新版本固件也可以,如果使用最新版本的固件不可以,可以烧录 V2016-1 固件对比验证)
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、Luatools 工具烧录内核固件和 demo 脚本代码
+
+3、烧录成功后,自动开机运行
+
+4、正常运行情况时的日志如下:
+
+```
+[000000000.744] I/user.main protobuf 001.000.000
+[000000000.753] I/user.protobuf 加载 protobuf 定义成功,共解析 85 字节
+[000000000.753] I/user.protobuf 编码成功,数据长度:22
+[000000000.754] I/user.protobuf 十六进制内容:0A0677656E64616C107B1A0A6162634071712E636F6D
+[000000000.754] I/user.json 编码成功,数据长度:47
+[000000000.754] I/user.json 数据内容:{"name":"wendal","id":123,"email":"abc@qq.com"}
+[000000000.755] I/user.protobuf 解码成功,数据内容: {"name":"wendal","id":123,"email":"abc@qq.com"}
+[000000000.755] I/user.protobuf 所有 protobuf 定义已清除
+```
+

+ 58 - 52
module/Air8101/demo/protobuf/main.lua

@@ -1,69 +1,75 @@
--- main.lua文件
--- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "protobuf_demo"
-VERSION = "1.0.0"
-
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
+@version 1.0
+@date    2025.11.05
+@author  马梦阳
+@usage
+
+本demo演示的核心功能为:
+1.protobuf 的编码与解码;
+
+更多说明参考本目录下的 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 = "protobuf"
+VERSION = "001.000.000"
+
+
+-- 在日志中打印项目名和项目版本号
 log.info("main", PROJECT, VERSION)
 
 
+-- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
+-- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
+if wdt then
+    --配置喂狗超时时间为9秒钟
+    wdt.init(9000)
+    --启动一个循环定时器,每隔3秒钟喂一次狗
+    sys.timerLoopStart(wdt.feed, 3000)
+end
 
-sys.taskInit(function()
-
-        if not protobuf then
-                log.info("protobuf", "this demo need protobuf lib")
-                return
-        end
-
-        -- 加载 pb 文件, 这个是从pbtxt 转换得到的
-        -- 下载资源到模块时不需要下载pbtxt,需要下载person.pb文件
-        -- 转换命令: protoc.exe -o person.pb person.pbtxt
-        -- protoc.exe 下载地址: https://github.com/protocolbuffers/protobuf/releases
-        local pb_file = "/luadb/person.pb"
 
-        if io.exists(pb_file) then
-                protobuf.load(io.readFile(pb_file))
-                --如果该文件存在,会发布一个事件 pb_file_exists
-                sys.publish("pb_file_exists")
-        else
-                log.info("protobuf","Failed to load file")
+-- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
+-- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
+-- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
+-- 启动errDump日志存储并且上传功能,600秒上传一次
+-- if errDump then
+--     errDump.config(true, 600)
+-- end
 
-        end
 
-        local tb = {
-                name = "wendal",
-                id = 123,
-                email = "abc@qq.com"
-        }
+-- 使用LuatOS开发的任何一个项目,都强烈建议使用远程升级FOTA功能
+-- 可以使用合宙的iot.openluat.com平台进行远程升级
+-- 也可以使用客户自己搭建的平台进行远程升级
+-- 远程升级的详细用法,可以参考fota的demo进行使用
 
-        sys.waitUntil("pb_file_exists")
 
-        sys.wait(1000)
-        -- 用 protobuf 编码数据
-        local pbdata = protobuf.encode("Person", tb)
-        if pbdata then
-                -- 打印数据长度. 编码后的数据含不可见字符, toHex是方便显示
-                log.info("protobuf", "encode",  #pbdata, (pbdata:toHex()))
-        end
-        -- 用 json 编码数据, 用于对比大小
-        local jdata = json.encode(tb)
-        if jdata then
-                log.info("json", #jdata, jdata)
-        end
-        -- 可见 protobuffs 比 json 节省很多空间
+-- 启动一个循环定时器
+-- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
+-- 方便分析内存使用是否有异常
+-- sys.timerLoopStart(function()
+--     log.info("mem.lua", rtos.meminfo())
+--     log.info("mem.sys", rtos.meminfo("sys"))
+-- end, 3000)
 
-        -- 后续是演示解码
-        local re = protobuf.decode("Person", pbdata)
-        if re then
--- 打印数据, 因为table不能直接显示, 这里转成json来显示
-log.info("protobuf", "decode", json.encode(re))
-        end
 
-
-end)
+-- 加载 protobuf 应用模块
+require "protobuf_app"
 
 
 -- 用户代码已结束---------------------------------------------
 -- 结尾总是这一句
 sys.run()
 -- sys.run()之后后面不要加任何语句!!!!!
-

+ 3 - 6
module/Air8101/demo/protobuf/person.pbtxt

@@ -1,6 +1,3 @@
-syntax = "proto2";
-message Person {
-  optional string name = 1;
-  optional int32 id = 2;
-  optional string email = 3;
-}
+name: "wendal"
+id: 123
+email: "abc@qq.com"

+ 6 - 0
module/Air8101/demo/protobuf/person.proto

@@ -0,0 +1,6 @@
+syntax = "proto2";
+message Person {
+  optional string name = 1;
+  optional int32 id = 2;
+  optional string email = 3;
+}

+ 83 - 0
module/Air8101/demo/protobuf/protobuf_app.lua

@@ -0,0 +1,83 @@
+--[[
+@module  protobuf_app
+@summary protobuf 编解码功能模块
+@version 1.0
+@date    2025.11.05
+@author  马梦阳
+@usage
+本功能模块演示的内容为:
+1.加载 protobuf 定义文件;
+2.将符合 protobuf 定义的 Lua table 数据编码为二进制数据;
+3.使用 json 编码同样的 Lua table 数据后,对比 protobuf 和 json 编码后数据的大小;
+4.将二进制数据解码为 Lua table 数据;
+5.清除所有已加载的定义数据;
+
+
+本文件没有对外接口,直接在 main.lua 中 require "protobuf_app" 就可以加载运行;
+]]
+
+
+local function main_task()
+    -- 加载 pb 文件, 这个是 proto 经过 protoc.exe 编译后生成的二进制文件
+    -- 下载资源到模块时不需要下载 proto 文件
+    -- 转换命令: protoc -o person.pb person.proto
+    -- protoc.exe 下载地址: https://github.com/protocolbuffers/protobuf/releases
+    local pb_file = "/luadb/person.pb"
+
+    local tbdata = {
+        name = "wendal",
+        id = 123,
+        email = "abc@qq.com"
+    }
+
+    if io.exists(pb_file) then
+        local success, bytesRead = protobuf.load(io.readFile(pb_file))
+        if not success then
+            log.info("protobuf", "加载 protobuf 定义失败,已读取 " .. bytesRead .. " 字节")
+            return
+        else
+            log.info("protobuf", "加载 protobuf 定义成功,共解析 " .. bytesRead .. " 字节")
+        end
+    else
+        log.info("protobuf", "pb 文件不存在")
+        return
+    end
+
+    -- 编码数据;
+    local pbdata = protobuf.encode("Person", tbdata)
+    if pbdata then
+        -- 编码成功,编码后的数据通常包含不可见字符;
+        -- 打印长度和十六进制内容(便于调试);
+        log.info("protobuf", "编码成功,数据长度:" .. #pbdata)
+        log.info("protobuf", "十六进制内容:" .. pbdata:toHex())
+    else
+        log.info("protobuf", "编码失败:数据格式或类型不匹配")
+    end
+
+    -- 对比 protobuf 编码和 json 编码的大小;
+    local jdata = json.encode(tbdata)
+    if jdata then
+        log.info("json", "编码成功,数据长度:" .. #jdata)
+        log.info("json", "数据内容:" .. jdata)
+    else
+        log.info("json", "编码失败:数据格式或类型不匹配")
+    end
+    -- 可见 protobuffs 比 json 节省很多空间;
+
+    -- 数据解码;
+    local tbdata = protobuf.decode("Person", pbdata)
+    if tbdata then
+        -- 解码后的数据为 Lua table 格式,需要转化为 json 进行显示;
+        log.info("protobuf", "解码成功,数据内容:", json.encode(tbdata))
+    else
+        log.info("protobuf", "解码失败")
+    end
+
+    -- 清除所有已加载的定义数据;
+    protobuf.clear()
+    log.info("protobuf", "所有 protobuf 定义已清除")
+end
+
+-- 创建并启动一个 task
+-- 用于运行 main_task 函数
+sys.taskInit(main_task)

+ 98 - 0
module/Air8101/demo/protobuf/readme.md

@@ -0,0 +1,98 @@
+## 演示模块概述
+
+1、main.lua:主程序入口;
+
+2、protobuf_app.lua:protobuf 编解码功能模块;
+
+## 演示功能概述
+
+使用 Air8101 核心板搭配 protobuf 库演示 protobuf 编码与解码功能;
+
+1、加载 protobuf 定义文件;
+
+2、将符合 protobuf 定义的 Lua table 数据编码为二进制数据;
+
+3、使用 json 编码同样的 Lua table 数据后,对比 protobuf 和 json 编码后数据的大小;
+
+4、将二进制数据解码为 Lua table 数据;
+
+5、清除所有已加载的定义数据;
+
+注意事项:
+
+1、protobuf 库支持 Proto2 和 Proto3 协议版本;
+
+2、person.proto 文件是消息结构定义文件(Schema),它是人类可读的文本文件,使用 Protobuf IDL 语法,该文件定义了消息类型 Person 的结构(字段名、类型、编号等),文件中示例内容如下:
+
+```protobuf
+syntax = "proto2";
+
+message Person {
+  optional string name = 1;
+  optional int32 id = 2;
+  optional string email = 3;
+}
+```
+
+该文件需要由开发者手动创建编写,语言规范参考:
+
+Protocol Buffers 官方语言指南(proto3):[Language Guide (proto 3) | Protocol Buffers Documentation](https://protobuf.dev/programming-guides/proto3/) ;
+
+Protocol Buffers 官方语言指南(proto2):[Language Guide (proto 2) | Protocol Buffers Documentation](https://protobuf.dev/programming-guides/proto2/) ;
+
+3、person.pb 文件是 Schema 描述的二进制文件(FileDescriptorSet),是 person.proto 经过 protoc -o 编译后生成的二进制元数据,该文件包含 Person 消息的完整结构描述(字段名、编号、类型),用于被 protobuf.load() 加载,供后续 protobuf.encode() 和 protobuf.decode() 能知道 Person 的结构,从而正确编解码;
+
+4、关于如何得到 person.pb 文件说明如下:
+
+- 需要先下载 protoc.exe,下载链接:https://github.com/protocolbuffers/protobuf/releases ;
+- 在 protoc.exe 文件目录下打开 CMD,输入 protoc -o person.pb person.proto 即可生成 person.pb 文件,前提需要同目录下包含 person.proto 文件;
+
+5、person.pbtxt 文件是用户数据的文本表示(TextFormat),它是人类可读的文本文件,表示一个具体的 Person 消息实例,内容是字段赋值,文件中示例内容如下:
+
+```textproto
+name: "wendal"
+id: 123
+email: "abc@qq.com"
+```
+
+该文件需要用户手动编写(用于配置、测试),或者通过程序把用户数据以人类可读的文本格式保存在 .pbtxt 文件下;
+
+该文件内容需要遵循 Protobuf 文本格式语法规范(Text Format Syntax),语言规范参考:
+
+Protobuf Text Format 官方语言规范(草案):[Text Format Language Specification | Protocol Buffers Documentation](https://protobuf.dev/reference/protobuf/textformat-spec/) ;
+
+6、person.pbtxt 文件用于调试、写测试用例、作为配置文件,可被支持 TextFormat 的 Protobuf 库解析为内存对象,在 LuatOS 中不使用 .pbtxt 文件(protobuf 库只支持 binary encode/decode,也就是 .pb 文件);
+
+## 演示硬件环境
+
+1、Air8101 核心板一块
+
+2、TYPE-C USB数据线一根
+
+## 演示软件环境
+
+1、[Luatools下载调试工具](https://docs.openluat.com/air8000/luatos/common/download/)
+
+2、[Air8101 V1006 版本](https://docs.openluat.com/air8101/luatos/firmware/)(理论上最新版本固件也可以,如果使用最新版本的固件不可以,可以烧录 V1006-1 固件对比验证)
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、Luatools 工具烧录内核固件和 demo 脚本代码
+
+3、烧录成功后,自动开机运行
+
+4、正常运行情况时的日志如下:
+
+```
+[000000000.744] I/user.main protobuf 001.000.000
+[000000000.753] I/user.protobuf 加载 protobuf 定义成功,共解析 85 字节
+[000000000.753] I/user.protobuf 编码成功,数据长度:22
+[000000000.754] I/user.protobuf 十六进制内容:0A0677656E64616C107B1A0A6162634071712E636F6D
+[000000000.754] I/user.json 编码成功,数据长度:47
+[000000000.754] I/user.json 数据内容:{"name":"wendal","id":123,"email":"abc@qq.com"}
+[000000000.755] I/user.protobuf 解码成功,数据内容: {"name":"wendal","id":123,"email":"abc@qq.com"}
+[000000000.755] I/user.protobuf 所有 protobuf 定义已清除
+```
+