freeRTOS操作系统机器人实现
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

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