#include "bsp_config.h" #ifdef USE_LUA_ST #include #include "lua_base.h" #include "main.h" #include "bsp_pin.h" #include "stmflash.h" #include "led.h" #include "common.h" #include "rd_time.h" #include "bsp_usb.h" void Rd_lstm32EnableStrong(void) { // 用于强符号覆盖的锚点 } volatile uint8_t g_lua_stop_request; // 用于标识是否跳出Lua死循环(依赖于死循环中调用st.ms延时) void l_exit_hook(lua_State *L, lua_Debug *ar) { if (g_lua_stop_request) { g_lua_stop_request = 0; luaL_error(L, "__STOP_REQUESTED__"); } } typedef struct { GPIO_TypeDef *port; uint16_t pin; uint8_t mode; } stm32_pin_t; static GPIO_TypeDef* get_port_from_char(const char *p_str) { switch(p_str[0]) { case 'A': case 'a': return GPIOA; case 'B': case 'b': return GPIOB; case 'C': case 'c': return GPIOC; #ifdef IOC_100PIN case 'D': case 'd': return GPIOD; case 'E': case 'e': return GPIOE; case 'F': case 'f': return GPIOF; #endif default: return NULL; } } int get_pin_from_char(const char *p_str) { if (p_str == NULL) return -1; const char *num_start = &p_str[1]; if (*num_start < '0' || *num_start > '9') return -1; int pin_num = atoi(num_start); return pin_num; } // 构造函数: stm32.Pin("A5", mode) static int l_pin_new(lua_State *L) { const char *port_str = luaL_checkstring(L, 1); if ((port_str[0] == 'A' || port_str[0] == 'a') && (port_str[1] == '2' || port_str[1] == '3')) { return luaL_error(L, "PA2,PA3 is used!"); } int mode = luaL_optinteger(L, 2, 1); // 配合修改为默认上拉输入 GPIO_TypeDef *port = get_port_from_char(port_str); if (!port) { return luaL_error(L, "Invalid port"); } int pin_num = get_pin_from_char(port_str); if (pin_num < 0) { return luaL_error(L, "Invalid pin"); } uint16_t pin = (1 << pin_num); stm32_pin_t *p = (stm32_pin_t*)lua_newuserdata(L, sizeof(stm32_pin_t)); p->port = port; p->pin = pin; p->mode = mode; bsp_pin_init(port, pin, mode); // 设置 Metatable (以便使用冒号语法 :write) luaL_getmetatable(L, "stm32.PinMT"); lua_setmetatable(L, -2); return 1; } // 方法: pin:write(value) static int l_pin_write(lua_State *L) { stm32_pin_t *p = (stm32_pin_t*)luaL_checkudata(L, 1, "stm32.PinMT"); int val = luaL_checkinteger(L, 2); HAL_GPIO_WritePin(p->port, p->pin, val ? GPIO_PIN_SET : GPIO_PIN_RESET); return 0; } // 方法: pin:read() static int l_pin_read(lua_State *L) { stm32_pin_t *p = (stm32_pin_t*)luaL_checkudata(L, 1, "stm32.PinMT"); GPIO_PinState state = HAL_GPIO_ReadPin(p->port, p->pin); lua_pushinteger(L, (state == GPIO_PIN_SET) ? 1 : 0); return 1; } // 方法: pin:toggle() static int l_pin_toggle(lua_State *L) { stm32_pin_t *p = (stm32_pin_t*)luaL_checkudata(L, 1, "stm32.PinMT"); HAL_GPIO_TogglePin(p->port, p->pin); return 0; } int luaopen_stm32_pin(lua_State *L) { // 1. 注册 Metatable (保持不变) if (luaL_newmetatable(L, "stm32.PinMT")) { lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); const luaL_Reg pin_methods[] = { {"write", l_pin_write}, {"read", l_pin_read}, {"toggle", l_pin_toggle}, {NULL, NULL} }; const luaL_Reg *l; for (l = pin_methods; l->name != NULL; l++) { lua_pushcfunction(L, l->func); lua_setfield(L, -2, l->name); } } lua_pop(L, 1); // 2. 创建模块表 lua_newtable(L); // 3. 注册构造函数 lua_pushcfunction(L, l_pin_new); lua_setfield(L, -2, "new"); return 1; } typedef struct { void *luastate; int pinref; rd_led_t *led; } stm32_led_t; static void lua_pin_write_bridge(l_led_t *pLed, int state) { // 1. 基础安全检查 if (!pLed || !pLed->m_pLuaState || pLed->m_iPinRef == LUA_NOREF) { return; } lua_State *L = (lua_State *)pLed->m_pLuaState; int top = lua_gettop(L); // 记录当前栈顶,用于最后恢复 // 2. 从 Registry 获取 Pin 对象 lua_rawgeti(L, LUA_REGISTRYINDEX, pLed->m_iPinRef); if (!lua_isuserdata(L, -1)) { lua_pop(L, 1); return; } // 3. 获取 "write" 方法 lua_getfield(L, -1, "write"); // 验证方法是否存在且为函数 if (!lua_isfunction(L, -1)) { lua_pop(L, 2); return; } // 4. 构建调用栈:目标格式 [func, self, arg] // 当前栈: [pin, write_func] (index: -2, -1) // 步骤 A: 将 write_func 移到栈底 (相对于这三个元素) // 使用 lua_insert(L, -3) 会将栈顶元素(-1) 插入到 -3 位置 // 但这里我们只有两个元素,更直观的方法是重新排列: // 我们希望顺序是:func, pin(self), state // 当前: -2=pin, -1=func lua_insert(L, -2); // 执行后: -2=func, -1=pin => 栈: [func, pin] // 步骤 B: 压入参数 state lua_pushinteger(L, state ? 1 : 0); // 5. 执行调用 (2 个参数,0 个返回值) if (lua_pcall(L, 2, 0, 0) != LUA_OK) { const char *err = lua_tostring(L, -1); log_e("LED Callback Error: %s", err); lua_pop(L, 1); } // 6. 恢复栈平衡 lua_settop(L, top); } static int l_led_new(lua_State *L) { luaL_checkudata(L, 1, "stm32.PinMT"); int active_logic = luaL_optinteger(L, 2, 0); // 这里设置Pin:write(0)表示灯亮 const char *light_mode = luaL_optstring(L, 3, "500,500"); // 表示500msactive_logic为0,500msactive_logic为1 int loop_cnt = luaL_optinteger(L, 4, -1); // 这里默认传-1表示无限重复light_mode stm32_led_t *pLed = (stm32_led_t*)lua_newuserdata(L, sizeof(stm32_led_t)); if (!pLed) { return luaL_error(L, "Failed to allocate LED userdata"); } memset(pLed, 0, sizeof(stm32_led_t)); pLed->luastate = (void *)L; lua_pushvalue(L, 1); pLed->pinref = luaL_ref(L, LUA_REGISTRYINDEX); rd_led_t *pLed_t = rd_LedCreate(active_logic, light_mode, loop_cnt, lua_pin_write_bridge, (l_led_t *)pLed); pLed->led = pLed_t; luaL_getmetatable(L, "stm32.ledMT"); lua_setmetatable(L, -2); // 将元表设置给刚才创建的 userdata return 1; } // 方法: led:off() static int l_led_off(lua_State *L) { stm32_led_t *p = (stm32_led_t*)luaL_checkudata(L, 1, "stm32.ledMT"); rd_LedOff(p->led); return 0; } // 方法: led:on() static int l_led_on(lua_State *L) { stm32_led_t *p = (stm32_led_t*)luaL_checkudata(L, 1, "stm32.ledMT"); rd_LedOn(p->led); return 0; } // 方法: led:start() static int l_led_start(lua_State *L) { stm32_led_t *p = (stm32_led_t*)luaL_checkudata(L, 1, "stm32.ledMT"); int iRet = rd_LedStart(p->led); lua_pushinteger(L, iRet); return 1; } // 方法: led:stop() static int l_led_stop(lua_State *L) { stm32_led_t *p = (stm32_led_t*)luaL_checkudata(L, 1, "stm32.ledMT"); int iRet = rd_LedStop(p->led); lua_pushinteger(L, iRet); return 1; } // 方法: led:setmode() static int l_led_setmode(lua_State *L) { stm32_led_t *p = (stm32_led_t*)luaL_checkudata(L, 1, "stm32.ledMT"); const char *light_mode = luaL_optstring(L, 2, "500,500"); int loop_cnt = luaL_optinteger(L, 3, -1); int iRet = rd_LedDynamicChangeLightMode(p->led, light_mode, loop_cnt); lua_pushinteger(L, iRet); return 1; } static int l_led_gc(lua_State *L) { stm32_led_t *p = (stm32_led_t*)luaL_checkudata(L, 1, "stm32.ledMT"); if (p && p->led) { rd_LedDelete(p->led); p->led = NULL; if (p->pinref != LUA_NOREF) { luaL_unref(L, LUA_REGISTRYINDEX, p->pinref); p->pinref = LUA_NOREF; } } return 0; } // 方法: st.ledproc() static int l_led_proc(lua_State *L) { rd_LedProcess(); return 0; } int luaopen_stm32_led(lua_State *L) { // 1. 注册 Metatable (保持不变) if (luaL_newmetatable(L, "stm32.ledMT")) { lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, l_led_gc); lua_setfield(L, -2, "__gc"); const luaL_Reg methods[] = { {"off", l_led_off}, {"on", l_led_on}, {"start", l_led_start}, {"stop", l_led_stop}, {"setmode", l_led_setmode}, {NULL, NULL} }; const luaL_Reg *l; for (l = methods; l->name != NULL; l++) { lua_pushcfunction(L, l->func); lua_setfield(L, -2, l->name); } } lua_pop(L, 1); // 2. 创建模块表 lua_newtable(L); // 3. 注册构造函数 lua_pushcfunction(L, l_led_new); lua_setfield(L, -2, "new"); return 1; } static int l_delay_ms(lua_State *L) { int ms = luaL_checkinteger(L, 1); if (ms < 0) { return luaL_error(L, "delay_ms: time cannot be negative"); } Rd_Delay(ms); return 0; } static int l_delay_us(lua_State *L) { int us = luaL_checkinteger(L, 1); if (us < 0) { return luaL_error(L, "delay_us: time cannot be negative"); } delay_us(us); return 0; } static int l_reboot(lua_State *L) { NVIC_SystemReset(); return 0; } #ifdef USE_FREERTOS static int l_ps(lua_State *L) { void ShowTaskList(void); ShowTaskList(); return 0; } static int l_free(lua_State *L) { void ShowHeapSize(void); ShowHeapSize(); return 0; } #endif #ifdef USE_LWIP static int l_lwip(lua_State *L) { void stats_display(void); stats_display(); return 0; } #endif #ifdef USE_ONCHIP_FLASH #define LUA_START_ADDR 0x08020000UL #define LUA_BUFFER_MAX 1024 //用于缓存Lua脚本的buffer大小 #define SCRIPT_HEADER_ADDR LUA_START_ADDR #define SCRIPT_DATA_ADDR (LUA_START_ADDR + sizeof(ScriptHeader)) extern ssize_t _read(int file, char *ptr, ssize_t len); typedef enum { UPLOAD_WAIT_1 = 0,// 等待第一个@ UPLOAD_WAIT_2, // 等待第二个@ UPLOAD_WAIT_3, // 等待第三个@ UPLOAD_END_1, // 等待第一个结束@ UPLOAD_END_2, // 等待第二个结束@ UPLOAD_END_3 // 等待第三个结束@ } UpLoadStat; uint8_t g_uploadstat = UPLOAD_WAIT_1; uint8_t g_luabuffer[LUA_BUFFER_MAX]; int g_luabuffer_pos = 0; int g_data_len = 0; typedef struct { uint32_t magic; // 例如 0x4C756153 ("LuaS") uint32_t length; // 脚本长度 } ScriptHeader; typedef struct { uint32_t addr; uint32_t left; uint8_t buffer[LUA_BUFFER_MAX]; int buf_idx; int buf_len; } LuaFlashReader; const char* flash_reader(lua_State *L, void *ud, size_t *size) { LuaFlashReader *ctx = (LuaFlashReader*)ud; if (ctx->left == 0) { *size = 0; return NULL; } if (ctx->buf_idx >= ctx->buf_len) { size_t read_len = (ctx->left > sizeof(ctx->buffer)) ? sizeof(ctx->buffer) : ctx->left; STMFLASH_Read(ctx->addr, ctx->buffer, read_len); ctx->addr += read_len; ctx->left -= read_len; ctx->buf_idx = 0; ctx->buf_len = read_len; } int available = ctx->buf_len - ctx->buf_idx; *size = available; const char *ptr = (const char*)(ctx->buffer + ctx->buf_idx); ctx->buf_idx += available; return ptr; } static int l_run_script(lua_State *L) { ScriptHeader hdr; STMFLASH_Read(SCRIPT_HEADER_ADDR, (uint8_t*)&hdr, sizeof(hdr)); if (hdr.magic != 0x4C756153) { luaL_error(L, "No valid script found.\r\n"); return 0; } lua_print("Loading script (len=%ld)...\r\n", hdr.length); LuaFlashReader ctx = { .addr = SCRIPT_DATA_ADDR, .left = hdr.length, .buf_idx = 0, .buf_len = 0 }; int status = lua_load(L, flash_reader, &ctx, "script"); if (status == LUA_OK) { if (lua_pcall(L, 0, 0, 0) != LUA_OK) { lua_print("Runtime Error: %s\r\n", lua_tostring(L, -1)); lua_pop(L, 1); } } else { lua_print("Load Error: %s\r\n", lua_tostring(L, -1)); lua_pop(L, 1); } return 0; } static int flush_buffer() { if (g_luabuffer_pos > 0) { if (STMFLASH_Write(SCRIPT_DATA_ADDR + g_data_len, g_luabuffer, g_luabuffer_pos) != HAL_OK) { lua_print("\r\n[ERR] Flash Write Failed!\r\n"); return -1; } g_data_len += g_luabuffer_pos; g_luabuffer_pos = 0; } return 0; } static int Upload_FSM(uint8_t byte) { switch (g_uploadstat) { case UPLOAD_WAIT_1: if (byte == '@') g_uploadstat = UPLOAD_WAIT_2; break; case UPLOAD_WAIT_2: if (byte == '@') g_uploadstat = UPLOAD_WAIT_3; else g_uploadstat = UPLOAD_WAIT_1; break; case UPLOAD_WAIT_3: if (byte == '@') { g_uploadstat = UPLOAD_END_1; if (STMFLASH_EraseByAddress(LUA_START_ADDR) != HAL_OK) { lua_print("\r\n[ERR] Erase Failed!\r\n"); return -1; } else { g_uploadstat = UPLOAD_END_1; g_luabuffer_pos = 0; g_data_len = 0; } } else { g_uploadstat = UPLOAD_WAIT_1; } break; case UPLOAD_END_1: if (byte == '@') { g_uploadstat = UPLOAD_END_2; } else { g_luabuffer[g_luabuffer_pos++] = byte; if (g_luabuffer_pos >= LUA_BUFFER_MAX) { if (0 != flush_buffer()) return -1; } } break; case UPLOAD_END_2: if (byte == '@') { g_uploadstat = UPLOAD_END_3; } else { lua_print("\r\n[ERR] Protocol error in end sequence.\r\nPlease check and send again!\r\n"); g_uploadstat = UPLOAD_WAIT_1; g_luabuffer_pos = 0; g_data_len = 0; } break; case UPLOAD_END_3: if (byte == '@') { if (0 != flush_buffer()) return -1; ScriptHeader hdr; hdr.magic = 0x4C756153; hdr.length = g_data_len; STMFLASH_Write(SCRIPT_HEADER_ADDR, (uint8_t*)&hdr, sizeof(hdr)); lua_print("\r\n[SUCCESS] Upload Complete! Len: %d. Rebooting...\r\n", g_data_len); Rd_Delay(100); NVIC_SystemReset(); } else { lua_print("\r\n[ERR] Protocol error in end sequence.\r\nPlease check and send again!\r\n"); g_uploadstat = UPLOAD_WAIT_1; g_luabuffer_pos = 0; g_data_len = 0; } break; default: g_uploadstat = UPLOAD_WAIT_1; break; } return 0; } static int l_upload(lua_State *L) { lua_print("\r\nupload start!\r\nPlease send lua string @@@...@@@\r\n"); while (1) { char ch[256]; ssize_t ret = _read(STDIN_FILENO, ch, sizeof(ch)); if (ret > 0) { for(int i=0; i