You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
752 lines
18 KiB
752 lines
18 KiB
|
3 days ago
|
#include "bsp_config.h"
|
||
|
|
#ifdef USE_LUA_ST
|
||
|
|
#include <unistd.h>
|
||
|
|
#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<ret; i++)
|
||
|
|
{
|
||
|
|
if (0 != Upload_FSM(ch[i])) return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
int luaopen_stm32(lua_State *L)
|
||
|
|
{
|
||
|
|
lua_sethook(L, l_exit_hook, LUA_MASKCOUNT, 1000000);
|
||
|
|
|
||
|
|
lua_newtable(L);
|
||
|
|
|
||
|
|
lua_pushinteger(L, 0); lua_setfield(L, -2, "OUT");
|
||
|
|
lua_pushinteger(L, 1); lua_setfield(L, -2, "UP");
|
||
|
|
lua_pushinteger(L, 2); lua_setfield(L, -2, "DOWN");
|
||
|
|
lua_pushinteger(L, 3); lua_setfield(L, -2, "HEX");
|
||
|
|
|
||
|
|
// 直接将 C 函数压栈,然后设置到表中
|
||
|
|
lua_pushcfunction(L, l_delay_ms);
|
||
|
|
lua_setfield(L, -2, "ms"); // st.ms = l_delay_ms
|
||
|
|
|
||
|
|
lua_pushcfunction(L, l_delay_us);
|
||
|
|
lua_setfield(L, -2, "us"); // st.us = l_delay_us
|
||
|
|
|
||
|
|
#ifdef USE_ONCHIP_FLASH
|
||
|
|
lua_pushcfunction(L, l_upload);
|
||
|
|
lua_setfield(L, -2, "update"); // st.update = l_upload
|
||
|
|
|
||
|
|
lua_pushcfunction(L, l_run_script);
|
||
|
|
lua_setfield(L, -2, "run"); // st.run = l_run_script
|
||
|
|
#endif
|
||
|
|
lua_pushcfunction(L, l_led_proc);
|
||
|
|
lua_setfield(L, -2, "ledproc");
|
||
|
|
|
||
|
|
// 1. 加载 Pin 模块
|
||
|
|
lua_pushcfunction(L, luaopen_stm32_pin);
|
||
|
|
lua_call(L, 0, 1);
|
||
|
|
// 此时栈顶 (-1) 是 Pin 模块表: { new = function }
|
||
|
|
|
||
|
|
// 2. 提取 "new" 函数
|
||
|
|
lua_getfield(L, -1, "new");
|
||
|
|
// 此时栈结构: [-2: Pin模块表, -1: l_pin_new 函数]
|
||
|
|
|
||
|
|
// 3. 将这个函数赋值给主表的 "Pin" 字段
|
||
|
|
// 这样 s.Pin 就直接指向 l_pin_new 函数
|
||
|
|
lua_setfield(L, -3, "Pin");
|
||
|
|
// 此时栈结构: [-1: Pin模块表] (s.Pin 已经设置好了)
|
||
|
|
|
||
|
|
// 4. 清理栈,弹出临时的 Pin 模块表
|
||
|
|
lua_pop(L, 1);
|
||
|
|
|
||
|
|
lua_pushcfunction(L, luaopen_stm32_led);
|
||
|
|
lua_call(L, 0, 1);
|
||
|
|
lua_getfield(L, -1, "new");
|
||
|
|
lua_setfield(L, -3, "led");
|
||
|
|
lua_pop(L, 1);
|
||
|
|
|
||
|
|
#ifdef USE_LUA_ST_UART
|
||
|
|
int luaopen_stm32_com(lua_State *L);
|
||
|
|
lua_pushcfunction(L, luaopen_stm32_com);
|
||
|
|
lua_call(L, 0, 1);
|
||
|
|
lua_getfield(L, -1, "new");
|
||
|
|
lua_setfield(L, -3, "COM");
|
||
|
|
lua_pop(L, 1);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifdef USE_LUA_ST_CAN
|
||
|
|
int luaopen_stm32_can(lua_State *L);
|
||
|
|
lua_pushcfunction(L, luaopen_stm32_can);
|
||
|
|
lua_call(L, 0, 1);
|
||
|
|
lua_getfield(L, -1, "new");
|
||
|
|
lua_setfield(L, -3, "CAN");
|
||
|
|
lua_pop(L, 1);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
lua_setglobal(L, "st");
|
||
|
|
|
||
|
|
lua_pushcfunction(L, l_reboot);
|
||
|
|
lua_setglobal(L, "reboot"); // reboot = l_reboot
|
||
|
|
|
||
|
|
#ifdef USE_FREERTOS
|
||
|
|
lua_pushcfunction(L, l_ps);
|
||
|
|
lua_setglobal(L, "ps"); // ps = l_ps
|
||
|
|
|
||
|
|
lua_pushcfunction(L, l_free);
|
||
|
|
lua_setglobal(L, "free"); // ps = l_ps
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifdef USE_LWIP
|
||
|
|
lua_pushcfunction(L, l_lwip);
|
||
|
|
lua_setglobal(L, "lwip"); // lwip = l_lwip
|
||
|
|
#endif
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
void StartLuaREPL(void *argument)
|
||
|
|
{
|
||
|
|
lua_init(luaprint_stdout);
|
||
|
|
while(1)
|
||
|
|
{
|
||
|
|
lua_repl(NULL, -1, 1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif
|