Lizongdi 6 days ago
parent
commit
129b63dde0
  1. 1
      CMakeLists.txt
  2. 6
      RBcore/CMakeLists.txt
  3. 12
      RBcore/drv_interface.c
  4. 1
      RBcore/include/BHBF.h
  5. 2
      RBcore/include/msg_center.h
  6. 96
      README.md
  7. 10
      bspMCU/l_stm32.c
  8. 15
      library/protobuf/CMakeLists.txt
  9. 0
      library/protobuf/include/pb.h
  10. 0
      library/protobuf/include/pb_common.h
  11. 0
      library/protobuf/include/pb_decode.h
  12. 0
      library/protobuf/include/pb_encode.h
  13. 0
      library/protobuf/pb_common.c
  14. 0
      library/protobuf/pb_decode.c
  15. 0
      library/protobuf/pb_encode.c
  16. 22
      lua/CMakeLists.txt
  17. 2
      lua/lua.c
  18. 2
      lua/lua_base.h
  19. 774
      lua/pb_lua.c
  20. 53
      lua/pb_lua.h
  21. 123
      lua/pb_lua_desc.h
  22. 24
      lua/pb_lua_registry.c

1
CMakeLists.txt

@ -114,6 +114,7 @@ add_module(log library/log OFF OFF)
add_module(common library/common ON OFF)
add_module(list library/list OFF OFF)
add_module(ringbuffer library/ringbuffer OFF OFF)
add_module(protobuf library/protobuf OFF OFF)
add_module(peripheral peripheral OFF ON)
add_module(littlefs library/littlefs OFF OFF)
add_module(lua lua OFF ON)

6
RBcore/CMakeLists.txt

@ -15,6 +15,12 @@ else()
message(FATAL_ERROR "[${TARGET_NAME}] Dependency 'bspMCU' not found.")
endif()
if(TARGET protobuf)
target_link_libraries(${TARGET_NAME} PUBLIC protobuf)
else()
message(FATAL_ERROR "[${TARGET_NAME}] Dependency 'protobuf' not found.")
endif()
get_filename_component(ROBOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.." ABSOLUTE)
file(GLOB PROJECT_DIRS LIST_DIRECTORIES true "${ROBOT_DIR}/project/*")
foreach(PROJ_DIR ${PROJECT_DIRS})

12
RBcore/drv_interface.c

@ -22,6 +22,7 @@
#include "FreeRTOS.h"
#include "bsp_EEPROM.h"
#include "msg_center.h"
#include "lua_base.h"
/*----------------------------------------------*
* 外部变量说明 *
*----------------------------------------------*/
@ -276,12 +277,18 @@ void controller_init(void);
void daemon_Init(void);
void Timer_Init(void);
int l_setCV(lua_State *L)
{
GF_BSP_EEPROM_WriteBytes((uint8_t*)&g_stCV, GF_BSP_EEPROM_CV_struct_define_Start_Address, sizeof(CV_struct_define));
return 0;
}
void Drv_InterfaceInit(void)
{
GF_BSP_EEPROM_Init();
MsgCenter_Init();
GF_BSP_EEPROM_ReadBytes((uint8_t *)&g_stCV, GF_BSP_EEPROM_CV_struct_define_Start_Address, sizeof(CV_struct_define));
#if 1
MsgCenter_Init();
client_setting_Init();
// ground_manger_init();
@ -337,5 +344,6 @@ void Drv_InterfaceInit(void)
daemon_Init();
//Timer_Init();
#endif
log_i("BingooRobot Init success\nversion: %s", Rd_GetBuildTime());
}

1
RBcore/include/BHBF.h

@ -93,7 +93,6 @@ typedef enum {
GET_MOTOR_FAULT_CODE, // 获取错误码(电机回码)
GET_DAEMON_CODE, // 获取daemon错误码
GET_MOTOR_OK, // 获取电机初始化完毕
CMD_PAINTGUN, // 控制喷枪
CMD_STRAIGHT_DRIVE_FINISH, // CMD_STRAIGHT_DRIVE命令停止后回调
CMD_TURN_ANGLE_FINISH, // CMD_TURN_ANGLE命令停止后回调
CMD_STOP_AFTER_PAINTOFF, // 先关枪后停车

2
RBcore/include/msg_center.h

@ -49,7 +49,7 @@ extern "C"{
typedef struct {
uint32_t m_uiSrcModule; // 源模块ID
uint32_t m_uiDstModule; // 目标模块ID
BHBF_Cmd_e m_uiMsgID; // 消息ID(命令字)
uint32_t m_uiMsgID; // 消息ID(命令字)
uint32_t m_uiDataLen; // 数据长度
uint8_t m_aucData[MSG_CENTER_MAX_DATA_SIZE]; // 消息数据
} Msg_t;

96
README.md

@ -2,9 +2,94 @@
## 写在前面
新代码架构使用cmake配合cubeide编译,使用cubemx修改ioc配置的方式进行维护。需要将cubeide升级至v2版本,由于v2起cubeide与cubemx分成了两个独立软件,因此如果要修改ioc配置的话还需要额外安装cubemx。安装包在部门共享文件夹内的`/vol1/@team/SW_Group/STM32相关文件及安装包等`有安装包。
新代码架构使用cmake配合cubeide编译,使用cubemx修改ioc配置的方式进行维护。需要将cubeide升级至v2版本,由于v2起cubeide与cubemx分成了两个独立软件,因此如果要修改ioc配置的话还需要额外安装cubemx。安装包在部门共享文件夹内的`/vol1/@team/SW_Group/STM32相关文件及安装包等`有安装包。考虑到易维护性以及代码授权问题,该工程采用了Git submodule的方式来确保公共部分代码不会被随意修改,所以需要先引入git的部分知识。
### 使用cubeide导入工程
## Git使用
在软件开发过程中经常会遇到迭代修改问题:即在一个项目中反复修改或优化某一个功能,代码变动很大,然后最后甲方的一句”我觉得还是用最开始那一版吧”经常把我们搞得焦头烂额。而业界一般常用git或svn来进行代码维度的版本管理,我们目前内部在用的是郭大佬搭建的[git平台](http://123.207.52.103:3000/),但是据我调研,大家目前都在把git当作一个云盘来使用而忽略了它的很多高级功能,此文章目的在于带大家了解一些git的基础操作和进阶操作。这里优先讲解我用到过的,其他的待大家完善。
### 安装Git(Windows下)
在[飞牛](http://192.168.18.234:5666/)的`/vol1/@team/SW_Group/提效软件`目录下(也就是主界面进去后依次点击**文件管理->团队文件->SW_Group->提效软件**)找到`Git-2.34.1-64-bit.exe`安装包并进行安装,安装选项较多无脑点下一步即可,当然也可以问一下AI那些选项都是什么意思让它给提提建议但一般都无伤大雅。
然后由于git默认的图形化界面很蠢,这里建议大家使用vscode的图形化界面进行日常代码提交。不过由于vscode插件不支持submodule命令,所以首次拉取工程时还是需要用到git命令行,大家继续往下看就知道了。
### 使用vscode的git插件拉取工程
vscode是自带git插件的,可以很方便地进行git基础操作,接下来演示如何从git远程仓库拉取本工程代码。
1. 新建一个文件夹用vscode打开。
2. vscode切换到git视图点击初始化按钮,如下图所示:
![image-20261012104010595](typora/image-20261012104010595.png)
3. 然后依次点击这里的三个点,`Remote`和`Add Remote`,如下图所示:
![image-20261012104115587](typora/image-20261012104115587.png)
4. 顶部会有一个位置让你输入git链接,我们输入`http://123.207.52.103:3000/LiZongdi/robot_h743.git`**按回车**,然后又会有一个文本框,这是给我们的本地仓库取名字的,一般习惯输入`origin`**按回车**
5. 本地仓库与远程仓库建立完联系之后,然后还是按下图所示顺序点击按钮进行拉取操作(也就是下载代码)**注意:如果第一个pull报错,就选下边的pull from然后会弹出一个框让你输入分支名,此时输入master或者点下边那个默认的即可拉取成功**
![image-20261012104614719](typora/image-20261012104614719.png)
6. 到这里就拉取完成了,然后大家会发现直接编译是不行的,因为robot文件夹下没有内容,这就是前文说到的submodule。简单来说就是git支持将另一个仓库作为子模块链接,这样再配合给不同的子模块不同的读写权限,就实现了代码的分层管理。vscode插件不支持git的submodule系列命令,所以大家要借助命令行操作(可以直接跳转到下一节第三步)。
### 使用git命令行拉取工程
除了使用插件之外,笔者还是更习惯使用命令行拉取仓库,这里重新讲解一下。
1. 还是新建文件夹,然后在文件夹内部右键**Git Bash Here**,安装完git后一般就会默认有这个选项了。随后会打开一个命令行交互界面。
![image-20261012110045631](typora/image-20261012110045631.png)
2. 依次输出如下命令(#号及其后汉字是注释不用输入):
```shell
git init #对应上一节的第二步初始化
git remote add origin http://123.207.52.103:3000/LiZongdi/robot_h743.git #对应上一节的第三四步关联仓库
git pull origin master #对应上一节的第五步拉取仓库
```
随后会看到类似如下输出(拉取需要时间可能需要几秒钟)
```shell
remote: Counting objects: 1043, done.
remote: Compressing objects: 100% (923/923), done.
remote: Total 1043 (delta 341), reused 636 (delta 95)
Receiving objects: 100% (1043/1043), 4.12 MiB | 929.00 KiB/s, done.
Resolving deltas: 100% (341/341), done.
From http://123.207.52.103:3000/LiZongdi/robot_h743
* branch master -> FETCH_HEAD
* [new branch] master -> origin/master
```
这就表示拉取完成了
3. 接下来拉取子库,输入如下命令:
```shell
git submodule update --init --recursive #update命令表示根据分支信息更新子库,init表示初始化子库(即首次拉取),recursive表示递归处理子库中包含的子子库。
```
这次需要的时间可能更长,输出类似:
```shell
Submodule 'robot' (http://123.207.52.103:3000/LiZongdi/robot.git) registered for path 'robot'
Cloning into 'D:/vedio/robot_old/robot'...
Submodule path 'robot': checked out 'ce5f7173b646b2fe0685798ef177f181b2dcca23'
Submodule 'project' (http://123.207.52.103:3000/LiZongdi/project.git) registered for path 'robot/project'
Submodule 'project_old' (http://123.207.52.103:3000/LiZongdi/project_old.git) registered for path 'robot/project_old'
Cloning into 'D:/vedio/robot_old/robot/project'...
Cloning into 'D:/vedio/robot_old/robot/project_old'...
Submodule path 'robot/project': checked out '86e867c5d8efd261ce78e0ee480771e8b6e8a7f7'
Submodule path 'robot/project_old': checked out '63e4150140333db80803088c1c56b01be5a9b994'
```
到这里大家就可以继续回去用vscode插件进行提交等操作了。vscode图形化插件在这方面的优势还是很大的。
## 使用cubeide导入工程
1. 打开cubeidev2版本
2. 依次点击顶部面板的File-->Import打开导入界面
@ -22,13 +107,6 @@
![image-20260930093413357](/typora/image-20260930093413357.png)
## Git使用
### 写在前面
在软件开发过程中经常会遇到迭代修改问题:即在一个项目中反复修改或优化某一个功能,代码变动很大,然后最后甲方的一句”我觉得还是用最开始那一版吧”经常把我们搞得焦头烂额。而业界一般常用git或svn来进行代码维度的版本管理,我们目前内部在用的是郭大佬搭建的[git平台](http://123.207.52.103:3000/),但是据我调研,大家目前都在把git当作一个云盘来使用而忽略了它的很多高级功能,此文章目的在于带大家了解一些git的基础操作和进阶操作。这里优先讲解我用到过的,其他的待大家完善。
### 安装Git(Windows下)
在[飞牛](http://192.168.18.234:5666/)的`/vol1/@team/SW_Group/提效软件`目录下(也就是主界面进去后依次点击**文件管理->团队文件->SW_Group->提效软件**)找到`Git-2.34.1-64-bit.exe`安装包并进行安装,安装选项较多无脑点下一步即可,当然也可以问一下AI那些选项都是什么意思让它给提提建议但一般都无伤大雅。
## 关于cmake与CMakePresets.json
大家一定注意到了根文件夹下的CMakePresets.json文件,这个文件就是cmake实现可裁剪模块化配置的关键文件。其中描述了开启哪些编译选项。CMakePresets.json文件的工作原理实际上就是代替命令行cmake中的裁剪配置命令参数,cmake会在每次预构建时读取CMakePresets.json文件内容并在build下生成编译中间文件。因此**每次修改完CMakePresets.json内容后如果需要其生效需要手动删除build文件夹重新触发cmake预编译**。

10
bspMCU/l_stm32.c

@ -9,6 +9,7 @@
#include "common.h"
#include "rd_time.h"
#include "bsp_usb.h"
#include "pb_lua.h"
volatile uint8_t g_lua_stop_request; // 用于标识是否跳出Lua死循环(依赖于死循环中调用st.ms延时)
@ -444,7 +445,7 @@ static int l_mount (lua_State *L)
}
#endif
#ifdef BUILD_RBCORE
#ifdef BUILD_PROTOBUF
static int l_sendto(lua_State *L)
{
int MsgCenter_SendTo(const char *pszDstName, uint32_t uiMsgID, const void *pData, uint32_t uiDataLen);
@ -708,6 +709,7 @@ static int l_upload(lua_State *L)
}
#endif
extern int l_setCV(lua_State *L);
int luaopen_stm32(lua_State *L)
{
lua_sethook(L, l_exit_hook, LUA_MASKCOUNT, 1000000);
@ -796,8 +798,12 @@ int luaopen_stm32(lua_State *L)
lua_register_help(L, "mount", l_mount, "mount littlefs disk");
#endif
#ifdef BUILD_RBCORE
#ifdef BUILD_PROTOBUF
lua_register_help(L, "sendto", l_sendto, "Send msg: sendto(dst,id,data)");
lua_register_help(L, "pb_dump", l_pb_dump, "pb_dump(\"CV_struct_define\", cv) -- pretty print");
lua_register_help(L, "pb_ref", l_pb_ref, "cv = pb_ref(\"CV\") -- live view of C global; pv.Value = 999");
lua_register_help(L, "setCV", l_setCV, "set CV to EEPROM");
pb_lua_open(L);
#endif
return 1;

15
library/protobuf/CMakeLists.txt

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.10)
set(COMMON_CMAKE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt")
if(EXISTS ${COMMON_CMAKE_PATH})
include(${COMMON_CMAKE_PATH})
else()
message(FATAL_ERROR "Cannot find common build logic at ${COMMON_CMAKE_PATH}")
endif()
if(TARGET common)
target_link_libraries(${TARGET_NAME} PUBLIC common)
else()
message(FATAL_ERROR "[${TARGET_NAME}] Dependency 'common' not found.")
endif()

0
RBcore/include/pb.h → library/protobuf/include/pb.h

0
RBcore/include/pb_common.h → library/protobuf/include/pb_common.h

0
RBcore/include/pb_decode.h → library/protobuf/include/pb_decode.h

0
RBcore/include/pb_encode.h → library/protobuf/include/pb_encode.h

0
RBcore/pb_common.c → library/protobuf/pb_common.c

0
RBcore/pb_decode.c → library/protobuf/pb_decode.c

0
RBcore/pb_encode.c → library/protobuf/pb_encode.c

22
lua/CMakeLists.txt

@ -19,3 +19,25 @@ if(TARGET platform_Linux)
else()
message(WARNING "[lua] Dependency 'platform_Linux' not found.")
endif()
if(TARGET protobuf)
target_link_libraries(${TARGET_NAME} PUBLIC protobuf)
else()
message(STATUS "[${TARGET_NAME}] Dependency 'protobuf' not found.")
endif()
get_filename_component(ROBOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.." ABSOLUTE)
file(GLOB PROJECT_DIRS LIST_DIRECTORIES true "${ROBOT_DIR}/project/*")
foreach(PROJ_DIR ${PROJECT_DIRS})
if(IS_DIRECTORY "${PROJ_DIR}")
get_filename_component(PROJ_NAME "${PROJ_DIR}" NAME)
string(TOUPPER "${PROJ_NAME}" PROJ_NAME_UPPER)
if(BUILD_${PROJ_NAME_UPPER})
set(PROTOBUF_PSOURCE "${PROJ_DIR}/Protobuf/PSource")
if(EXISTS "${PROTOBUF_PSOURCE}")
target_include_directories(${TARGET_NAME} PUBLIC "${PROTOBUF_PSOURCE}")
message(STATUS "[${TARGET_NAME}] Auto-detected protobuf include: ${PROTOBUF_PSOURCE}")
endif()
endif()
endif()
endforeach()

2
lua/lua.c

@ -92,7 +92,7 @@ static char *trim(char *str)
return str;
}
static void print_number_fixed3(double num)
void print_number_fixed3(double num)
{
if (NULL == lua_print) return;

2
lua/lua_base.h

@ -99,6 +99,8 @@ extern lua_output lua_print;
* routines' or functions' implementations *
*----------------------------------------------*/
int lua_init(lua_output _lua_print);
/* 拆分整数/小数部分打印浮点数(保留小数点后三位),不依赖 printf 的 %f/%g(适用于无浮点打印支持的平台) */
void print_number_fixed3(double num);
int lua_repl(char *_pcBuffer, int _iSize, int _iEcho);
void luaprint_stdout(const char *fmt, ...);
void lua_register_help(lua_State *L, const char *name, lua_CFunction func, const char *description);

774
lua/pb_lua.c

@ -0,0 +1,774 @@
/******************************************************************************
版权所有 (C), 2018-2099, Radkil
******************************************************************************
文 件 名 : pb_lua.c
版 本 号 : 初稿
功 能 描 述 : nanopb 消息的 Lua 桥接:table <-> C struct <-> protobuf 字节流
Lua 侧约定:
- 二进制一律 Lua string(与 COM:read/write 直通)
- 纯 table 表示消息;t.Value = 999 即改成员
- nil = 字段缺省(OPTIONAL 不出现在线上)
- 枚举字段为整数值(与 .proto 枚举编号一致,无名字表)
******************************************************************************/
#ifdef BUILD_PROTOBUF
#include <string.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include "lua_base.h"
#include "pb_lua.h"
#include "pb_lua_desc.h"
#include "pb.h"
#include "pb_encode.h"
#include "pb_decode.h"
#include "bsp_CV.pb.h"
/* 结构体/编码缓冲上限(当前最大消息 ~130B 结构 / 118B 编码,留足余量) */
#define PB_LUA_MAX_STRUCT 256
#define PB_LUA_MAX_ENCODED 256
/*======================================================================
* 消息注册表: 由 tools/gen_proto_ui.py --pb_lua_registry 生成
* pb_lua_registry.c 提供 g_pb_msgs / g_pb_msgs_count 强符号。
* 字段表内容仍走 Type_FIELDLIST X-macro(见 pb_lua_desc.h)。
*====================================================================*/
extern CV_struct_define g_stCV;
/*======================================================================
* 命名全局绑定注册表(pb_ref 用)
*====================================================================*/
#define PB_LUA_MAX_BINDINGS 8
typedef struct {
const char *name;
void *ptr;
const pb_lua_msg_t *msg;
} pb_lua_binding_t;
static pb_lua_binding_t g_pb_bindings[PB_LUA_MAX_BINDINGS];
static size_t g_pb_nbindings;
/*======================================================================
* 查找辅助
*====================================================================*/
static size_t pb_lua_strnlen(const char *s, size_t max)
{
size_t n = 0;
while (n < max && s[n] != '\0')
n++;
return n;
}
static const pb_lua_msg_t *pb_lua_find_msg_or_null(const char *name)
{
for (int i = 0; i < g_pb_msgs_count; i++) {
if (strcmp(g_pb_msgs[i]->name, name) == 0)
return g_pb_msgs[i];
}
return NULL;
}
static const pb_lua_msg_t *pb_lua_find_msg(lua_State *L, const char *name)
{
const pb_lua_msg_t *m = pb_lua_find_msg_or_null(name);
if (m != NULL)
return m;
/* known 列表从注册表动态拼接(生成 registry 后零手改) */
char known[256];
size_t off = 0;
known[0] = '\0';
for (int i = 0; i < g_pb_msgs_count && off + 32 < sizeof(known); i++) {
int w = snprintf(known + off, sizeof(known) - off, "%s%s",
(i ? ", " : ""), g_pb_msgs[i]->name);
if (w <= 0) break;
off += (size_t)w;
}
luaL_error(L, "unknown message type '%s' (known: %s)", name, known);
return NULL;
}
int pb_lua_bind(const char *name, void *ptr, const char *msgtype)
{
const pb_lua_msg_t *m;
if (name == NULL || ptr == NULL)
return -1;
m = pb_lua_find_msg_or_null(msgtype);
if (m == NULL)
return -1;
for (size_t i = 0; i < g_pb_nbindings; i++) {
if (strcmp(g_pb_bindings[i].name, name) == 0) {
g_pb_bindings[i].ptr = ptr;
g_pb_bindings[i].msg = m;
return 0;
}
}
if (g_pb_nbindings >= PB_LUA_MAX_BINDINGS)
return -2;
g_pb_bindings[g_pb_nbindings].name = name;
g_pb_bindings[g_pb_nbindings].ptr = ptr;
g_pb_bindings[g_pb_nbindings].msg = m;
g_pb_nbindings++;
return 0;
}
static const pb_lua_field_t *pb_lua_find_field(const pb_lua_msg_t *m, const char *name)
{
for (size_t i = 0; i < m->nfields; i++) {
if (strcmp(m->fields[i].name, name) == 0)
return &m->fields[i];
}
return NULL;
}
/*======================================================================
* table → C struct(encode 方向)
*====================================================================*/
static void pb_lua_table_to_msg(lua_State *L, int tidx, const pb_lua_msg_t *m, void *msg);
static void pb_lua_set_one(lua_State *L, int vidx, const pb_lua_field_t *f, void *msg)
{
void *p = (char *)msg + f->offset;
switch (f->ltype) {
case PB_LUA_T_BOOL: {
bool v;
if (!lua_isboolean(L, vidx))
luaL_error(L, "field '%s': expected boolean", f->name);
v = lua_toboolean(L, vidx) ? true : false;
memcpy(p, &v, sizeof(v));
break;
}
case PB_LUA_T_INT32: {
int32_t v;
if (!lua_isinteger(L, vidx))
luaL_error(L, "field '%s': expected integer", f->name);
lua_Integer li = lua_tointeger(L, vidx);
if (li < (lua_Integer)INT32_MIN || li > (lua_Integer)INT32_MAX)
luaL_error(L, "field '%s': integer out of int32 range", f->name);
v = (int32_t)li;
memcpy(p, &v, sizeof(v));
break;
}
case PB_LUA_T_INT64: {
int64_t v;
if (!lua_isinteger(L, vidx))
luaL_error(L, "field '%s': expected integer", f->name);
v = (int64_t)lua_tointeger(L, vidx);
memcpy(p, &v, sizeof(v));
break;
}
case PB_LUA_T_DOUBLE: {
double v;
if (!lua_isnumber(L, vidx))
luaL_error(L, "field '%s': expected number", f->name);
v = (double)lua_tonumber(L, vidx);
memcpy(p, &v, sizeof(v));
break;
}
case PB_LUA_T_STRING: {
size_t len;
const char *s;
if (lua_type(L, vidx) != LUA_TSTRING)
luaL_error(L, "field '%s': expected string", f->name);
s = lua_tolstring(L, vidx, &len);
if (memchr(s, 0, len) != NULL)
luaL_error(L, "field '%s': string contains embedded NUL", f->name);
if (len >= f->size)
luaL_error(L, "field '%s': string too long (%u >= %u)",
f->name, (unsigned)len, (unsigned)f->size);
memset(p, 0, f->size);
memcpy(p, s, len);
break;
}
case PB_LUA_T_MESSAGE: {
if (lua_type(L, vidx) != LUA_TTABLE)
luaL_error(L, "field '%s': expected table", f->name);
memset(p, 0, f->size); /* 赋值 = 整体替换子消息(live 路径无预清零) */
pb_lua_table_to_msg(L, vidx, (const pb_lua_msg_t *)f->aux, p);
break;
}
default:
luaL_error(L, "field '%s': unsupported protobuf type", f->name);
break;
}
if (f->has_offset >= 0) {
bool has = true;
memcpy((char *)msg + f->has_offset, &has, sizeof(has));
}
}
static void pb_lua_table_to_msg(lua_State *L, int tidx, const pb_lua_msg_t *m, void *msg)
{
tidx = lua_absindex(L, tidx);
lua_pushnil(L);
while (lua_next(L, tidx) != 0) {
if (lua_type(L, -2) != LUA_TSTRING) {
luaL_error(L, "%s: field name must be a string", m->name);
return;
}
const char *key = lua_tostring(L, -2);
const pb_lua_field_t *f = pb_lua_find_field(m, key);
if (f == NULL) {
luaL_error(L, "unknown field '%s' in %s", key, m->name);
return;
}
if (lua_isnil(L, -1)) {
/* 理论上 lua_next 不返回 nil 值,防御处理:视为缺省 */
lua_pop(L, 1);
continue;
}
pb_lua_set_one(L, -1, f, msg);
lua_pop(L, 1);
}
}
/*======================================================================
* C struct → table(decode 方向)
*====================================================================*/
static void pb_lua_msg_to_table(lua_State *L, const void *msg, const pb_lua_msg_t *m);
static void pb_lua_get_one(lua_State *L, const void *msg, const pb_lua_field_t *f)
{
const void *p = (const char *)msg + f->offset;
switch (f->ltype) {
case PB_LUA_T_BOOL: {
bool v;
memcpy(&v, p, sizeof(v));
lua_pushboolean(L, v);
break;
}
case PB_LUA_T_INT32: {
int32_t v;
memcpy(&v, p, sizeof(v));
lua_pushinteger(L, (lua_Integer)v);
break;
}
case PB_LUA_T_INT64: {
int64_t v;
memcpy(&v, p, sizeof(v));
lua_pushinteger(L, (lua_Integer)v);
break;
}
case PB_LUA_T_DOUBLE: {
double v;
memcpy(&v, p, sizeof(v));
lua_pushnumber(L, (lua_Number)v);
break;
}
case PB_LUA_T_STRING: {
const char *s = (const char *)p;
lua_pushlstring(L, s, pb_lua_strnlen(s, f->size > 0 ? f->size - 1 : 0));
break;
}
case PB_LUA_T_MESSAGE: {
pb_lua_msg_to_table(L, p, (const pb_lua_msg_t *)f->aux);
break;
}
default:
lua_pushnil(L);
break;
}
}
/* OPTIONAL 且 has==false 的字段不进 table(nil = 缺省);SINGULAR 恒进 */
static int pb_lua_field_present(const void *msg, const pb_lua_field_t *f)
{
if (f->has_offset < 0)
return 1;
bool has;
memcpy(&has, (const char *)msg + f->has_offset, sizeof(has));
return has ? 1 : 0;
}
static void pb_lua_msg_to_table(lua_State *L, const void *msg, const pb_lua_msg_t *m)
{
lua_createtable(L, (int)m->nfields, 0);
for (size_t i = 0; i < m->nfields; i++) {
const pb_lua_field_t *f = &m->fields[i];
if (!pb_lua_field_present(msg, f))
continue;
pb_lua_get_one(L, msg, f);
lua_setfield(L, -2, f->name);
}
}
/*======================================================================
* dump:解析显示
*====================================================================*/
static void pb_lua_dump_indent(int depth)
{
for (int i = 0; i < depth; i++)
lua_print(" ");
}
static void pb_lua_dump_value(lua_State *L, int vidx, const pb_lua_field_t *f, int depth);
/* 递归打印 C 结构字段(不含外层花括号头) */
static void pb_lua_dump_msg_fields(const void *msg, const pb_lua_msg_t *m, int depth)
{
for (size_t i = 0; i < m->nfields; i++) {
const pb_lua_field_t *f = &m->fields[i];
if (!pb_lua_field_present(msg, f))
continue;
pb_lua_dump_indent(depth);
if (f->ltype == PB_LUA_T_MESSAGE) {
lua_print("%s {\n", f->name);
pb_lua_dump_msg_fields((const char *)msg + f->offset,
(const pb_lua_msg_t *)f->aux, depth + 1);
pb_lua_dump_indent(depth);
lua_print("}\n");
}
else {
lua_print("%s = ", f->name);
const void *p = (const char *)msg + f->offset;
switch (f->ltype) {
case PB_LUA_T_BOOL: {
bool v;
memcpy(&v, p, sizeof(v));
lua_print("%s", v ? "true" : "false");
break;
}
case PB_LUA_T_INT32: {
int32_t v;
memcpy(&v, p, sizeof(v));
lua_print("%d", v);
break;
}
case PB_LUA_T_INT64: {
int64_t v;
memcpy(&v, p, sizeof(v));
lua_print("%lld", (long long)v);
break;
}
case PB_LUA_T_DOUBLE: {
double v;
memcpy(&v, p, sizeof(v));
print_number_fixed3(v);
break;
}
case PB_LUA_T_STRING: {
const char *s = (const char *)p;
lua_print("\"%s\"", s);
break;
}
default:
lua_print("?");
break;
}
lua_print("\n");
}
}
}
static void pb_lua_dump_msg(const void *msg, const pb_lua_msg_t *m, int depth)
{
pb_lua_dump_indent(depth);
lua_print("%s {\n", m->name);
pb_lua_dump_msg_fields(msg, m, depth + 1);
pb_lua_dump_indent(depth);
lua_print("}\n");
}
/* 按 table 打印字段(不含外层花括号头,多余键标 [unknown] 置后) */
static void pb_lua_dump_table_fields(lua_State *L, int tidx, const pb_lua_msg_t *m, int depth)
{
tidx = lua_absindex(L, tidx);
for (size_t i = 0; i < m->nfields; i++) {
const pb_lua_field_t *f = &m->fields[i];
lua_getfield(L, tidx, f->name);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
continue;
}
pb_lua_dump_indent(depth);
if (f->ltype == PB_LUA_T_MESSAGE) {
lua_print("%s {\n", f->name);
pb_lua_dump_table_fields(L, -1, (const pb_lua_msg_t *)f->aux, depth + 1);
pb_lua_dump_indent(depth);
lua_print("}\n");
lua_pop(L, 1);
}
else {
lua_print("%s = ", f->name);
pb_lua_dump_value(L, -1, f, depth + 1);
lua_print("\n");
lua_pop(L, 1);
}
}
/* 多余键 */
lua_pushnil(L);
while (lua_next(L, tidx) != 0) {
if (lua_type(L, -2) == LUA_TSTRING) {
const char *key = lua_tostring(L, -2);
if (pb_lua_find_field(m, key) == NULL) {
pb_lua_dump_indent(depth);
lua_print("%s = ", key);
if (lua_type(L, -1) == LUA_TSTRING)
lua_print("\"%s\"", lua_tostring(L, -1));
else if (lua_isinteger(L, -1))
lua_print("%d", lua_tointeger(L, -1));
else if (lua_isnumber(L, -1))
print_number_fixed3((double)lua_tonumber(L, -1));
else if (lua_isboolean(L, -1))
lua_print("%s", lua_toboolean(L, -1) ? "true" : "false");
else
lua_print("%s", lua_typename(L, lua_type(L, -1)));
lua_print(" [unknown]\n");
}
}
lua_pop(L, 1);
}
}
static void pb_lua_dump_table(lua_State *L, int tidx, const pb_lua_msg_t *m, int depth)
{
tidx = lua_absindex(L, tidx);
pb_lua_dump_indent(depth);
lua_print("%s {\n", m->name);
pb_lua_dump_table_fields(L, tidx, m, depth + 1);
pb_lua_dump_indent(depth);
lua_print("}\n");
}
static void pb_lua_dump_value(lua_State *L, int vidx, const pb_lua_field_t *f, int depth)
{
(void)depth;
switch (f->ltype) {
case PB_LUA_T_BOOL:
lua_print("%s", lua_toboolean(L, vidx) ? "true" : "false");
break;
case PB_LUA_T_INT32:
case PB_LUA_T_INT64:
if (lua_isinteger(L, vidx))
lua_print("%d", lua_tointeger(L, vidx));
else
print_number_fixed3((double)lua_tonumber(L, vidx));
break;
case PB_LUA_T_DOUBLE:
print_number_fixed3((double)lua_tonumber(L, vidx));
break;
case PB_LUA_T_STRING:
lua_print("\"%s\"", lua_tostring(L, vidx));
break;
default:
lua_print("%s", lua_typename(L, lua_type(L, vidx)));
break;
}
}
static void pb_lua_dump_hex(const pb_byte_t *buf, size_t len)
{
size_t n = len > 64 ? 64 : len;
lua_print("hex:");
for (size_t i = 0; i < n; i++)
lua_print(" %02X", (unsigned)buf[i]);
if (len > n)
lua_print(" ...");
lua_print("\n");
}
/*======================================================================
* live userdata(PB_LIVE):C 全局/结构体指针的可写视图
*====================================================================*/
typedef struct {
void *ptr; /* 借用指针,不拥有内存(无 __gc) */
const pb_lua_msg_t *msg;
} pb_lua_live_t;
#define PB_LIVE_MT "PB_LIVE"
static int l_live_index(lua_State *L);
static int l_live_newindex(lua_State *L);
static int l_live_tostring(lua_State *L);
static int l_live_dump(lua_State *L);
static int l_live_encode(lua_State *L);
static int l_live_totable(lua_State *L);
static void pb_lua_live_open(lua_State *L)
{
if (!luaL_newmetatable(L, PB_LIVE_MT)) {
lua_pop(L, 1);
return;
}
lua_pushcfunction(L, l_live_index); lua_setfield(L, -2, "__index");
lua_pushcfunction(L, l_live_newindex); lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, l_live_tostring); lua_setfield(L, -2, "__tostring");
lua_pushcfunction(L, l_live_dump); lua_setfield(L, -2, "dump");
lua_pushcfunction(L, l_live_encode); lua_setfield(L, -2, "encode");
lua_pushcfunction(L, l_live_totable); lua_setfield(L, -2, "totable");
lua_pop(L, 1);
}
static void pb_lua_push_live(lua_State *L, void *ptr, const pb_lua_msg_t *m)
{
pb_lua_live_t *u = (pb_lua_live_t *)lua_newuserdata(L, sizeof *u);
u->ptr = ptr;
u->msg = m;
pb_lua_live_open(L); /* 确保 metatable 已注册(会 pop 掉) */
luaL_getmetatable(L, PB_LIVE_MT); /* 重新从 registry 取出 */
lua_setmetatable(L, -2);
}
/* 字段优先,方法 fallback;未知键报错(与 table 路径同文案)
* MESSAGE 字段: Mutable 语义 — 始终返回嵌套 live 视图, 首次进入置 has_
* (否则 p.Sub.Field = x 在零初始化上必炸; 与 C++ MutableMessage 对齐)。 */
static int l_live_index(lua_State *L)
{
pb_lua_live_t *u = (pb_lua_live_t *)luaL_checkudata(L, 1, PB_LIVE_MT);
const char *key = luaL_checkstring(L, 2);
const pb_lua_field_t *f = pb_lua_find_field(u->msg, key);
if (f != NULL) {
if (f->ltype == PB_LUA_T_MESSAGE) {
/* 嵌套消息可导航; 首次进入置 has_, encode 才会带上 */
if (f->has_offset >= 0) {
bool has;
memcpy(&has, (char *)u->ptr + f->has_offset, sizeof(has));
if (!has) {
has = true;
memcpy((char *)u->ptr + f->has_offset, &has, sizeof(has));
}
}
pb_lua_push_live(L, (char *)u->ptr + f->offset,
(const pb_lua_msg_t *)f->aux);
return 1;
}
if (!pb_lua_field_present(u->ptr, f)) {
lua_pushnil(L);
return 1;
}
pb_lua_get_one(L, u->ptr, f);
return 1;
}
lua_getmetatable(L, 1);
lua_getfield(L, -1, key);
if (!lua_isnil(L, -1))
return 1;
return luaL_error(L, "unknown field '%s' in %s", key, u->msg->name);
}
/* nil → 清 OPTIONAL 的 has_(SINGULAR 报错);其余走 set_one(自动置 has_=true) */
static int l_live_newindex(lua_State *L)
{
pb_lua_live_t *u = (pb_lua_live_t *)luaL_checkudata(L, 1, PB_LIVE_MT);
const char *key = luaL_checkstring(L, 2);
const pb_lua_field_t *f = pb_lua_find_field(u->msg, key);
if (f == NULL)
return luaL_error(L, "unknown field '%s' in %s", key, u->msg->name);
if (lua_isnil(L, 3)) {
bool has = false;
if (f->has_offset < 0)
return luaL_error(L, "field '%s' in %s: SINGULAR field cannot be cleared",
key, u->msg->name);
memcpy((char *)u->ptr + f->has_offset, &has, sizeof(has));
return 0;
}
pb_lua_set_one(L, 3, f, u->ptr);
return 0;
}
static int l_live_tostring(lua_State *L)
{
pb_lua_live_t *u = (pb_lua_live_t *)luaL_checkudata(L, 1, PB_LIVE_MT);
lua_pushfstring(L, "PB_LIVE(%s): %p", u->msg->name, u->ptr);
return 1;
}
static int l_live_dump(lua_State *L)
{
pb_lua_live_t *u = (pb_lua_live_t *)luaL_checkudata(L, 1, PB_LIVE_MT);
pb_lua_dump_msg(u->ptr, u->msg, 0);
return 0;
}
/* 直接从 C 内存编码,不经 table 往返 */
static int l_live_encode(lua_State *L)
{
pb_lua_live_t *u = (pb_lua_live_t *)luaL_checkudata(L, 1, PB_LIVE_MT);
if (u->msg->c_size > PB_LUA_MAX_STRUCT || u->msg->max_encoded > PB_LUA_MAX_ENCODED)
return luaL_error(L, "%s: message too large for static buffer", u->msg->name);
pb_byte_t buf[PB_LUA_MAX_ENCODED];
pb_ostream_t os = pb_ostream_from_buffer(buf, u->msg->max_encoded);
if (!pb_encode(&os, u->msg->msg, u->ptr))
return luaL_error(L, "%s encode failed: %s", u->msg->name, PB_GET_ERROR(&os));
lua_pushlstring(L, (const char *)buf, os.bytes_written);
return 1;
}
static int l_live_totable(lua_State *L)
{
pb_lua_live_t *u = (pb_lua_live_t *)luaL_checkudata(L, 1, PB_LIVE_MT);
pb_lua_msg_to_table(L, u->ptr, u->msg);
return 1;
}
int l_pb_ref(lua_State *L)
{
const char *name = luaL_checkstring(L, 1);
for (size_t i = 0; i < g_pb_nbindings; i++) {
if (strcmp(g_pb_bindings[i].name, name) == 0) {
pb_lua_push_live(L, g_pb_bindings[i].ptr, g_pb_bindings[i].msg);
return 1;
}
}
return luaL_error(L, "unknown pb global '%s'", name);
}
void pb_lua_open(lua_State *L)
{
pb_lua_live_open(L);
if (pb_lua_bind("CV", &g_stCV, "CV_struct_define") != 0)
luaL_error(L, "pb_lua_open: bind failed");
}
/*======================================================================
* Lua 全局函数
*====================================================================*/
int l_pb_encode(lua_State *L)
{
const pb_lua_msg_t *m = pb_lua_find_msg(L, luaL_checkstring(L, 1));
luaL_checktype(L, 2, LUA_TTABLE);
if (m->c_size > PB_LUA_MAX_STRUCT || m->max_encoded > PB_LUA_MAX_ENCODED)
return luaL_error(L, "%s: message too large for static buffer", m->name);
char msg[PB_LUA_MAX_STRUCT];
memset(msg, 0, m->c_size);
pb_lua_table_to_msg(L, 2, m, msg);
pb_byte_t buf[PB_LUA_MAX_ENCODED];
pb_ostream_t os = pb_ostream_from_buffer(buf, m->max_encoded);
if (!pb_encode(&os, m->msg, msg))
return luaL_error(L, "%s encode failed: %s", m->name, PB_GET_ERROR(&os));
lua_pushlstring(L, (const char *)buf, os.bytes_written);
return 1;
}
int l_pb_decode(lua_State *L)
{
const pb_lua_msg_t *m = pb_lua_find_msg(L, luaL_checkstring(L, 1));
size_t len;
const pb_byte_t *data = (const pb_byte_t *)luaL_checklstring(L, 2, &len);
if (m->c_size > PB_LUA_MAX_STRUCT)
return luaL_error(L, "%s: message too large for static buffer", m->name);
char msg[PB_LUA_MAX_STRUCT];
memset(msg, 0, m->c_size);
pb_istream_t is = pb_istream_from_buffer(data, len);
if (!pb_decode(&is, m->msg, msg))
return luaL_error(L, "%s decode failed: %s", m->name, PB_GET_ERROR(&is));
pb_lua_msg_to_table(L, msg, m);
return 1;
}
int l_pb_dump(lua_State *L)
{
const pb_lua_msg_t *m = pb_lua_find_msg(L, luaL_checkstring(L, 1));
{
pb_lua_live_t *u = (pb_lua_live_t *)luaL_testudata(L, 2, PB_LIVE_MT);
if (u != NULL) {
if (u->msg != m)
return luaL_error(L, "pb_dump: type mismatch: %s vs %s",
m->name, u->msg->name);
pb_lua_dump_msg(u->ptr, u->msg, 0);
return 0;
}
}
if (lua_type(L, 2) == LUA_TSTRING) {
size_t len;
const pb_byte_t *data = (const pb_byte_t *)lua_tolstring(L, 2, &len);
if (m->c_size > PB_LUA_MAX_STRUCT) {
lua_print("pb_dump: %s too large\n", m->name);
return 0;
}
char msg[PB_LUA_MAX_STRUCT];
memset(msg, 0, m->c_size);
pb_istream_t is = pb_istream_from_buffer(data, len);
if (!pb_decode(&is, m->msg, msg)) {
lua_print("pb_dump: %s decode failed: %s\n", m->name, PB_GET_ERROR(&is));
pb_lua_dump_hex(data, len);
return 0;
}
pb_lua_dump_msg(msg, m, 0);
}
else if (lua_type(L, 2) == LUA_TTABLE) {
pb_lua_dump_table(L, 2, m, 0);
}
else {
return luaL_error(L, "pb_dump: expected binary string, table, or pb_ref userdata");
}
return 0;
}
/* 全零模板:所有字段都置初值(嵌套消息递归展开),方便直接填值编码发送。
* 字段留在表里即视为 present;不想发到线上的字段设为 nil 即可。 */
static void pb_lua_new_table(lua_State *L, const pb_lua_msg_t *m)
{
lua_createtable(L, (int)m->nfields, 0);
for (size_t i = 0; i < m->nfields; i++) {
const pb_lua_field_t *f = &m->fields[i];
switch (f->ltype) {
case PB_LUA_T_BOOL:
lua_pushboolean(L, 0);
break;
case PB_LUA_T_INT32:
case PB_LUA_T_INT64:
lua_pushinteger(L, 0);
break;
case PB_LUA_T_DOUBLE:
lua_pushnumber(L, 0);
break;
case PB_LUA_T_STRING:
lua_pushstring(L, "");
break;
case PB_LUA_T_MESSAGE:
pb_lua_new_table(L, (const pb_lua_msg_t *)f->aux);
break;
default:
lua_pushnil(L);
break;
}
lua_setfield(L, -2, f->name);
}
}
int l_pb_new(lua_State *L)
{
const pb_lua_msg_t *m = pb_lua_find_msg(L, luaL_checkstring(L, 1));
pb_lua_new_table(L, m);
return 1;
}
#endif

53
lua/pb_lua.h

@ -0,0 +1,53 @@
/******************************************************************************
版权所有 (C), 2018-2099, Radkil
******************************************************************************
文 件 名 : pb_lua.h
版 本 号 : 初稿
功 能 描 述 : nanopb 消息的 Lua 序列化/反序列化桥接接口
******************************************************************************/
#ifndef __PB_LUA_H__
#define __PB_LUA_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifdef BUILD_PROTOBUF
#include "lua.h"
/*
* Lua 全局函数(由 lacmd.c 的 luaopen_default 注册):
* pb_encode("TPokemonPV", t) -> binary string
* pb_decode("TPokemonPV", bin) -> table
* pb_dump("TPokemonPV", bin|table) -- pretty print
* pb_new("TPokemonPV") -> zero-filled table (fill & encode)
* pb_ref("CV") -> live userdata view of a bound C global
* p.Field / p.Field = v -- read/write through to C memory
* p.Sub.Field = 10 -- 嵌套 MESSAGE: Mutable 语义, 首次进入置 has_
* p:dump() / p:encode() / p:totable()
*
* C 函数名带 l_ 前缀,避开 nanopb 导出的 pb_encode/pb_decode 符号。
*/
int l_pb_encode(lua_State *L);
int l_pb_decode(lua_State *L);
int l_pb_dump(lua_State *L);
int l_pb_new(lua_State *L);
int l_pb_ref(lua_State *L);
/* C 侧注册 API:把命名指针绑定到消息类型名(按 type name 查描述符)。
* 幂等:同名重复绑定更新指针。0=OK, -1=未知类型, -2=注册表满。
* 供业务模块在自身初始化处调用,不依赖 lua_State。 */
int pb_lua_bind(const char *name, void *ptr, const char *msgtype);
/* 每个 lua_State 一次(luaopen_default 调用):
* 创建 PB_LIVE metatable + 绑定 demo 全局 g_pokemon_pv。幂等。 */
void pb_lua_open(lua_State *L);
#endif
#ifdef __cplusplus
}
#endif
#endif /* __PB_LUA_H__ */

123
lua/pb_lua_desc.h

@ -0,0 +1,123 @@
/******************************************************************************
版权所有 (C), 2018-2099, Radkil
******************************************************************************
文 件 名 : pb_lua_desc.h
功能描述 : pb_lua 消息描述符类型 + X-macro。
由 pb_lua.c 与生成的 pb_lua_registry.c 共享。
字段表内容随 Type_FIELDLIST 自动; 消息注册由生成器维护。
******************************************************************************/
#ifndef __PB_LUA_DESC_H__
#define __PB_LUA_DESC_H__
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "pb.h"
typedef enum {
PB_LUA_T_BOOL = 0,
PB_LUA_T_INT32,
PB_LUA_T_INT64,
PB_LUA_T_DOUBLE,
PB_LUA_T_STRING,
PB_LUA_T_MESSAGE,
PB_LUA_T_UNSUPPORTED
} pb_lua_ftype_t;
typedef struct {
const char *name;
uint8_t tag;
uint8_t ltype; /* pb_lua_ftype_t */
uint16_t offset;
int16_t has_offset; /* -1 = 无 has_ */
uint16_t size;
const void *aux; /* MESSAGE→pb_lua_msg_t*; 否则 NULL */
} pb_lua_field_t;
typedef struct pb_lua_msg {
const char *name;
const pb_msgdesc_t *msg;
size_t c_size;
size_t max_encoded;
const pb_lua_field_t *fields;
size_t nfields;
} pb_lua_msg_t;
/*── X-macro: 由 Type_FIELDLIST 生成字段表 ────────────────────── */
#define PB_LUA_MSGREF_(type) (&type##_lua_desc)
#define PB_LUA_MSGREF(type) PB_LUA_MSGREF_(type)
#define PB_LUA_HAS_OPTIONAL(a, f) ((int16_t)offsetof(a, has_##f))
#define PB_LUA_HAS_REQUIRED(a, f) ((int16_t)-1)
#define PB_LUA_HAS_SINGULAR(a, f) ((int16_t)-1)
#define PB_LUA_HAS_REPEATED(a, f) ((int16_t)-1)
#define PB_LUA_AUX_NULL(a, f) NULL
#define PB_LUA_AUX_MESSAGE(a, f) PB_LUA_MSGREF(a##_##f##_MSGTYPE)
#define PB_LUA_AUX_MSG_W_CB(a, f) PB_LUA_AUX_MESSAGE(a, f)
#define PB_LUA_AUX_ENUM(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_UENUM(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_BOOL(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_INT32(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_INT64(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_DOUBLE(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_FLOAT(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_STRING(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_BYTES(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_UINT32(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_UINT64(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_SINT32(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_SINT64(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_FIXED32(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_FIXED64(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_SFIXED32(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_SFIXED64(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_EXTENSION(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_AUX_FIXED_LENGTH_BYTES(a, f) PB_LUA_AUX_NULL(a, f)
#define PB_LUA_FT_BOOL PB_LUA_T_BOOL
#define PB_LUA_FT_INT32 PB_LUA_T_INT32
#define PB_LUA_FT_INT64 PB_LUA_T_INT64
#define PB_LUA_FT_DOUBLE PB_LUA_T_DOUBLE
#define PB_LUA_FT_FLOAT PB_LUA_T_DOUBLE
#define PB_LUA_FT_ENUM PB_LUA_T_INT32
#define PB_LUA_FT_UENUM PB_LUA_T_INT32
#define PB_LUA_FT_STRING PB_LUA_T_STRING
#define PB_LUA_FT_MESSAGE PB_LUA_T_MESSAGE
#define PB_LUA_FT_MSG_W_CB PB_LUA_T_MESSAGE
#define PB_LUA_FT_BYTES PB_LUA_T_UNSUPPORTED
#define PB_LUA_FT_UINT32 PB_LUA_T_INT32
#define PB_LUA_FT_UINT64 PB_LUA_T_INT64
#define PB_LUA_FT_SINT32 PB_LUA_T_INT32
#define PB_LUA_FT_SINT64 PB_LUA_T_INT64
#define PB_LUA_FT_FIXED32 PB_LUA_T_INT32
#define PB_LUA_FT_FIXED64 PB_LUA_T_INT64
#define PB_LUA_FT_SFIXED32 PB_LUA_T_INT32
#define PB_LUA_FT_SFIXED64 PB_LUA_T_INT64
#define PB_LUA_FT_EXTENSION PB_LUA_T_UNSUPPORTED
#define PB_LUA_FT_FIXED_LENGTH_BYTES PB_LUA_T_UNSUPPORTED
#define PB_LUA_EMIT(a, atype, htype, ltype, name, tag) \
{ #name, (uint8_t)(tag), (uint8_t)PB_LUA_FT_##ltype, \
(uint16_t)offsetof(a, name), \
PB_LUA_HAS_##htype(a, name), \
(uint16_t)sizeof(((a *)0)->name), \
PB_LUA_AUX_##ltype(a, name) },
#define PB_LUA_FIELDS(Struct) Struct##_FIELDLIST(PB_LUA_EMIT, Struct)
#define PB_LUA_MSGDESC(Struct, StructName, MaxEnc) \
{ StructName, &Struct##_msg, sizeof(Struct), (MaxEnc), \
Struct##_fields_lua, \
sizeof(Struct##_fields_lua) / sizeof(Struct##_fields_lua[0]) }
/* ── 全局注册表(生成的 pb_lua_registry.c 强符号定义) ─────────── */
extern const pb_lua_msg_t *const g_pb_msgs[];
extern const int g_pb_msgs_count;
#endif /* __PB_LUA_DESC_H__ */

24
lua/pb_lua_registry.c

@ -0,0 +1,24 @@
/* Automatically generated by protoc-gen-proto_ui --pb_lua_registry. DO NOT EDIT. */
#ifdef BUILD_PROTOBUF
#include "pb_lua_desc.h"
#include "bsp_CV.pb.h"
static const pb_lua_field_t PID_Parameters_fields_lua[] = {
PB_LUA_FIELDS(PID_Parameters)
};
static const pb_lua_msg_t PID_Parameters_lua_desc =
PB_LUA_MSGDESC(PID_Parameters, "PID_Parameters", PID_Parameters_size);
static const pb_lua_field_t CV_struct_define_fields_lua[] = {
PB_LUA_FIELDS(CV_struct_define)
};
static const pb_lua_msg_t CV_struct_define_lua_desc =
PB_LUA_MSGDESC(CV_struct_define, "CV_struct_define", CV_struct_define_size);
const pb_lua_msg_t *const g_pb_msgs[] = {
&PID_Parameters_lua_desc, &CV_struct_define_lua_desc,
};
const int g_pb_msgs_count = (int)(sizeof(g_pb_msgs)/sizeof(g_pb_msgs[0]));
#endif
Loading…
Cancel
Save