Просмотр исходного кода

update: 把bsp/win32的修改也加上

1. 非rtos平台添加string.dump方法,用于对比lua/luac/luf格式的差异
2. 添加sys.lua做测试
Wendal Chen 4 лет назад
Родитель
Сommit
fdf8eee6e2

+ 4 - 0
bsp/win32/CMakeLists.txt

@@ -63,6 +63,10 @@ add_library(luat ${TOPROOT}/luat/modules/luat_main.c
                  ${TOPROOT}/components/sfd/luat_lib_sfd.c
                  ${TOPROOT}/components/sfd/luat_sfd_mem.c
                  ${TOPROOT}/components/sfd/luat_sfd_w25q.c
+                 ${TOPROOT}/components/luf/luat_lib_luf.c
+                 ${TOPROOT}/components/luf/luat_luf_dump.c
+                 ${TOPROOT}/components/luf/luat_luf_undump.c
+                 ${TOPROOT}/components/luf/luat_luf_cmp.c
                  ${TOPROOT}/luat/modules/crc.c
                  ${TOPROOT}/luat/vfs/luat_vfs.c
                  ${TOPROOT}/luat/vfs/luat_fs_luadb.c

+ 2 - 2
bsp/win32/luf_test/abc.lua

@@ -20,9 +20,9 @@ function abc.h2(name)
     end
     hi12345678901234567890123456789012345678902()
 
-    -- if sys == nil then
+    if sys == nil then
         
-    -- end
+    end
 
     return "hi, " .. name, function() end
 end

+ 10 - 27
bsp/win32/luf_test/main.lua

@@ -1,39 +1,22 @@
 
 log.info("main", "hi")
 
-local func = loadfile("abc.lua")
+local func = loadfile("sys.lua")
 log.info("func", func)
-buff = zbuff.create(16*1024)
+buff = zbuff.create(32*1024)
 data = luf.dump(func, false, buff)
 
 buff:write(data)
 
-log.info("data", #data)
-print(data:toHex())
-
-io.writeFile("abc.luf", data)
-
 func2 = luf.undump(data)
 
-if func2 then
-    log.info("func??", func2)
-    luf.cmp(func, func2)
-    local abc = func2()
-    log.info("table?", type(abc))
-    log.info("table?", json.encode(abc))
-    if abc.version then
-        log.info("abc", abc["version"])
-    else
-        log.info("abc", "no version")
-    end
-    if abc.h2 then
-        log.info("abc", abc.h2("wendal"))
-    else
-        log.info("abc", "no hi function")
+local sys = func2()
+
+sys.taskInit(function()
+    while true do
+        log.info("sys", "task loop")
+        sys.wait(1000)
     end
-    log.info("func??", "end", abc[1])
-else
-    log.info("func", "nil!!!")
-end
+end)
 
-os.exit(0)
+sys.run()

+ 14 - 0
bsp/win32/luf_test/main_luf.lua

@@ -0,0 +1,14 @@
+
+log.info("main", "hi")
+
+local func = loadfile("sys.lua")
+log.info("func", func)
+buff = zbuff.create(32*1024)
+data = luf.dump(func, false, buff)
+
+--buff:write(data)
+
+io.writeFile("sys.luf", data)
+io.writeFile("sys.luac", string.dump(func))
+
+os.exit(0)

+ 41 - 0
bsp/win32/luf_test/main_test.lua

@@ -0,0 +1,41 @@
+
+log.info("main", "hi")
+
+local func = loadfile("abc.lua")
+log.info("func", func)
+buff = zbuff.create(16*1024)
+data = luf.dump(func, false, buff)
+
+buff:write(data)
+
+log.info("data", #data)
+-- print(data:toHex())
+
+io.writeFile("abc.luf", data)
+io.writeFile("abc.luac", string.dump(func))
+io.writeFile("abc.luacs", string.dump(func, true))
+
+func2 = luf.undump(data)
+
+if func2 then
+    log.info("func??", func2)
+    -- luf.cmp(func, func2)
+    local abc = func2()
+    log.info("table?", type(abc))
+    log.info("table?", json.encode(abc))
+    if abc.version then
+        log.info("abc", abc["version"])
+    else
+        log.info("abc", "no version")
+    end
+    if abc.h2 then
+        log.info("abc", abc.h2("wendal"))
+    else
+        log.info("abc", "no hi function")
+    end
+    log.info("func??", "end", abc[1])
+else
+    log.info("func", "nil!!!")
+end
+
+os.exit(0)

+ 404 - 0
bsp/win32/luf_test/sys.lua

@@ -0,0 +1,404 @@
+--- 模块功能:Luat协程调度框架
+--module(..., package.seeall)
+
+local sys = {}
+
+local table = _G.table
+local unpack = table.unpack
+local rtos = _G.rtos
+local coroutine = _G.coroutine
+local log = _G.log
+
+-- lib脚本版本号,只要lib中的任何一个脚本做了修改,都需要更新此版本号
+SCRIPT_LIB_VER = "1.0.0"
+
+-- TaskID最大值
+local TASK_TIMER_ID_MAX = 0x1FFFFF
+-- msgId 最大值(请勿修改否则会发生msgId碰撞的危险)
+local MSG_TIMER_ID_MAX = 0x7FFFFF
+
+-- 任务定时器id
+local taskTimerId = 0
+-- 消息定时器id
+local msgId = TASK_TIMER_ID_MAX
+-- 定时器id表
+local timerPool = {}
+local taskTimerPool = {}
+--消息定时器参数表
+local para = {}
+--定时器是否循环表
+--local loop = {}
+--lua脚本运行出错时,是否回退为本地烧写的版本
+--local sRollBack = true
+
+_G.COROUTINE_ERROR_ROLL_BACK = true
+_G.COROUTINE_ERROR_RESTART = true
+
+-- 对coroutine.resume加一个修饰器用于捕获协程错误
+--local rawcoresume = coroutine.resume
+local function wrapper(co,...)
+    local arg = {...}
+    if not arg[1] then
+        local traceBack = debug.traceback(co)
+        traceBack = (traceBack and traceBack~="") and (arg[2].."\r\n"..traceBack) or arg[2]
+        log.error("coroutine.resume",traceBack)
+        --if errDump and type(errDump.appendErr)=="function" then
+        --    errDump.appendErr(traceBack)
+        --end
+        if _G.COROUTINE_ERROR_ROLL_BACK then
+            sys.timerStart(assert,500,false,traceBack)
+        elseif _G.COROUTINE_ERROR_RESTART then
+            rtos.reboot()
+        end
+    end
+    return ...
+end
+sys.coresume = function(...)
+    local arg = {...}
+    return wrapper(arg[1], coroutine.resume(...))
+end
+
+--- Task任务延时函数,只能用于任务函数中
+-- @number ms  整数,最大等待126322567毫秒
+-- @return 定时结束返回nil,被其他线程唤起返回调用线程传入的参数
+-- @usage sys.wait(30)
+function sys.wait(ms)
+    -- 参数检测,参数不能为负值
+    --assert(ms > 0, "The wait time cannot be negative!")
+    -- 选一个未使用的定时器ID给该任务线程
+    while true do
+        if taskTimerId >= TASK_TIMER_ID_MAX - 1 then
+            taskTimerId = 0
+        else
+            taskTimerId = taskTimerId + 1
+        end
+        if taskTimerPool[taskTimerId] == nil then
+            break
+        end
+    end
+    local timerid = taskTimerId
+    taskTimerPool[coroutine.running()] = timerid
+    timerPool[timerid] = coroutine.running()
+    -- 调用core的rtos定时器
+    if 1 ~= rtos.timer_start(timerid, ms) then log.debug("rtos.timer_start error") return end
+    -- 挂起调用的任务线程
+    local message = {coroutine.yield()}
+    if #message ~= 0 then
+        rtos.timer_stop(timerid)
+        taskTimerPool[coroutine.running()] = nil
+        timerPool[timerid] = nil
+        return unpack(message)
+    end
+end
+
+--- Task任务的条件等待函数(包括事件消息和定时器消息等条件),只能用于任务函数中。
+-- @param id 消息ID
+-- @number ms 等待超时时间,单位ms,最大等待126322567毫秒
+-- @return result 接收到消息返回true,超时返回false
+-- @return data 接收到消息返回消息参数
+-- @usage result, data = sys.waitUntil("SIM_IND", 120000)
+function sys.waitUntil(id, ms)
+    sys.subscribe(id, coroutine.running())
+    local message = ms and {sys.wait(ms)} or {coroutine.yield()}
+    sys.unsubscribe(id, coroutine.running())
+    return message[1] ~= nil, unpack(message, 2, #message)
+end
+
+--- Task任务的条件等待函数扩展(包括事件消息和定时器消息等条件),只能用于任务函数中。
+-- @param id 消息ID
+-- @number ms 等待超时时间,单位ms,最大等待126322567毫秒
+-- @return message 接收到消息返回message,超时返回false
+-- @return data 接收到消息返回消息参数
+-- @usage result, data = sys.waitUntilExt("SIM_IND", 120000)
+function sys.waitUntilExt(id, ms)
+    sys.subscribe(id, coroutine.running())
+    local message = ms and {sys.wait(ms)} or {coroutine.yield()}
+    sys.unsubscribe(id, coroutine.running())
+    if message[1] ~= nil then return unpack(message) end
+    return false
+end
+
+--- 创建一个任务线程,在模块最末行调用该函数并注册模块中的任务函数,main.lua导入该模块即可
+-- @param fun 任务函数名,用于resume唤醒时调用
+-- @param ... 任务函数fun的可变参数
+-- @return co  返回该任务的线程号
+-- @usage sys.taskInit(task1,'a','b')
+function sys.taskInit(fun, ...)
+    local co = coroutine.create(fun)
+    sys.coresume(co, ...)
+    return co
+end
+
+------------------------------------------ rtos消息回调处理部分 ------------------------------------------
+--[[
+函数名:cmpTable
+功能  :比较两个table的内容是否相同,注意:table中不能再包含table
+参数  :
+t1:第一个table
+t2:第二个table
+返回值:相同返回true,否则false
+]]
+local function cmpTable(t1, t2)
+    if not t2 then return #t1 == 0 end
+    if #t1 == #t2 then
+        for i = 1, #t1 do
+            if unpack(t1, i, i) ~= unpack(t2, i, i) then
+                return false
+            end
+        end
+        return true
+    end
+    return false
+end
+
+--- 关闭定时器
+-- @param val 值为number时,识别为定时器ID,值为回调函数时,需要传参数
+-- @param ... val值为函数时,函数的可变参数
+-- @return 无
+-- @usage timerStop(1)
+function sys.timerStop(val, ...)
+    -- val 为定时器ID
+    if type(val) == 'number' then
+        timerPool[val], para[val] = nil
+        rtos.timer_stop(val)
+    else
+        for k, v in pairs(timerPool) do
+            -- 回调函数相同
+            if type(v) == 'table' and v.cb == val or v == val then
+                -- 可变参数相同
+                if cmpTable({...}, para[k]) then
+                    rtos.timer_stop(k)
+                    timerPool[k], para[k] = nil
+                    break
+                end
+            end
+        end
+    end
+end
+
+--- 关闭同一回调函数的所有定时器
+-- @param fnc 定时器回调函数
+-- @return 无
+-- @usage timerStopAll(cbFnc)
+function sys.timerStopAll(fnc)
+    for k, v in pairs(timerPool) do
+        if type(v) == "table" and v.cb == fnc or v == fnc then
+            rtos.timer_stop(k)
+            timerPool[k], para[k] = nil
+        end
+    end
+end
+
+function sys.timerAdvStart(fnc, ms, _repeat, ...)
+    --回调函数和时长检测
+    --assert(fnc ~= nil, "sys.timerStart(first param) is nil !")
+    --assert(ms > 0, "sys.timerStart(Second parameter) is <= zero !")
+    -- 关闭完全相同的定时器
+    local arg = {...}
+    if #arg == 0 then
+        sys.timerStop(fnc)
+    else
+        sys.timerStop(fnc, ...)
+    end
+    -- 为定时器申请ID,ID值 1-20 留给任务,20-30留给消息专用定时器
+    while true do
+        if msgId >= MSG_TIMER_ID_MAX then msgId = TASK_TIMER_ID_MAX end
+        msgId = msgId + 1
+        if timerPool[msgId] == nil then
+            timerPool[msgId] = fnc
+            break
+        end
+    end
+    --调用底层接口启动定时器
+    if rtos.timer_start(msgId, ms, _repeat) ~= 1 then return end
+    --如果存在可变参数,在定时器参数表中保存参数
+    if #arg ~= 0 then
+        para[msgId] = arg
+    end
+    --返回定时器id
+    return msgId
+end
+
+--- 开启一个定时器
+-- @param fnc 定时器回调函数
+-- @number ms 整数,最大定时126322567毫秒
+-- @param ... 可变参数 fnc的参数
+-- @return number 定时器ID,如果失败,返回nil
+function sys.timerStart(fnc, ms, ...)
+    return sys.timerAdvStart(fnc, ms, 0, ...)
+end
+
+--- 开启一个循环定时器
+-- @param fnc 定时器回调函数
+-- @number ms 整数,最大定时126322567毫秒
+-- @param ... 可变参数 fnc的参数
+-- @return number 定时器ID,如果失败,返回nil
+function sys.timerLoopStart(fnc, ms, ...)
+    return sys.timerAdvStart(fnc, ms, -1, ...)
+end
+
+--- 判断某个定时器是否处于开启状态
+-- @param val 有两种形式
+--一种是开启定时器时返回的定时器id,此形式时不需要再传入可变参数...就能唯一标记一个定时器
+--另一种是开启定时器时的回调函数,此形式时必须再传入可变参数...才能唯一标记一个定时器
+-- @param ... 可变参数
+-- @return number 开启状态返回true,否则nil
+function sys.timerIsActive(val, ...)
+    if type(val) == "number" then
+        return timerPool[val]
+    else
+        for k, v in pairs(timerPool) do
+            if v == val then
+                if cmpTable({...}, para[k]) then return true end
+            end
+        end
+    end
+end
+
+
+------------------------------------------ LUA应用消息订阅/发布接口 ------------------------------------------
+-- 订阅者列表
+local subscribers = {}
+--内部消息队列
+local messageQueue = {}
+
+--- 订阅消息
+-- @param id 消息id
+-- @param callback 消息回调处理
+-- @usage subscribe("NET_STATUS_IND", callback)
+function sys.subscribe(id, callback)
+    --if not id or type(id) == "boolean" or (type(callback) ~= "function" and type(callback) ~= "thread") then
+    --    log.warn("warning: sys.subscribe invalid parameter", id, callback)
+    --    return
+    --end
+    --log.debug("sys", "subscribe", id, callback)
+    if type(id) == "table" then
+        -- 支持多topic订阅
+        for _, v in pairs(id) do sys.subscribe(v, callback) end
+        return
+    end
+    if not subscribers[id] then subscribers[id] = {} end
+    subscribers[id][callback] = true
+end
+--- 取消订阅消息
+-- @param id 消息id
+-- @param callback 消息回调处理
+-- @usage unsubscribe("NET_STATUS_IND", callback)
+function sys.unsubscribe(id, callback)
+    --if not id or type(id) == "boolean" or (type(callback) ~= "function" and type(callback) ~= "thread") then
+    --    log.warn("warning: sys.unsubscribe invalid parameter", id, callback)
+    --    return
+    --end
+    --log.debug("sys", "unsubscribe", id, callback)
+    if type(id) == "table" then
+        -- 支持多topic订阅
+        for _, v in pairs(id) do sys.unsubscribe(v, callback) end
+        return
+    end
+    if subscribers[id] then subscribers[id][callback] = nil end
+    -- 判断消息是否无其他订阅
+    for k, _ in pairs(subscribers[id]) do
+        return
+    end
+    subscribers[id] = nil
+end
+
+--- 发布内部消息,存储在内部消息队列中
+-- @param ... 可变参数,用户自定义
+-- @return 无
+-- @usage publish("NET_STATUS_IND")
+function sys.publish(...)
+    table.insert(messageQueue, {...})
+end
+
+-- 分发消息
+local function dispatch()
+    while true do
+        if #messageQueue == 0 then
+            break
+        end
+        local message = table.remove(messageQueue, 1)
+        if subscribers[message[1]] then
+            for callback, _ in pairs(subscribers[message[1]]) do
+                if type(callback) == "function" then
+                    callback(unpack(message, 2, #message))
+                elseif type(callback) == "thread" then
+                    sys.coresume(callback, unpack(message))
+                end
+            end
+        end
+    end
+end
+
+-- rtos消息回调
+--local handlers = {}
+--setmetatable(handlers, {__index = function() return function() end end, })
+
+--- 注册rtos消息回调处理函数
+-- @number id 消息类型id
+-- @param handler 消息处理函数
+-- @return 无
+-- @usage rtos.on(rtos.MSG_KEYPAD, function(param) handle keypad message end)
+--function sys.on(id, handler)
+--    handlers[id] = handler
+--end
+
+------------------------------------------ Luat 主调度框架  ------------------------------------------
+local function safeRun()
+    -- 分发内部消息
+    dispatch()
+    -- 阻塞读取外部消息
+    local msg, param, exparam = rtos.receive(rtos.INF_TIMEOUT)
+    --log.info("sys", msg, param, exparam, tableNSize(timerPool), tableNSize(para), tableNSize(taskTimerPool), tableNSize(subscribers))
+    -- 空消息?
+    if not msg or msg == 0 then
+        -- 无任何操作
+    -- 判断是否为定时器消息,并且消息是否注册
+    elseif msg == rtos.MSG_TIMER and timerPool[param] then
+        if param < TASK_TIMER_ID_MAX then
+            local taskId = timerPool[param]
+            timerPool[param] = nil
+            if taskTimerPool[taskId] == param then
+                taskTimerPool[taskId] = nil
+                sys.coresume(taskId)
+            end
+        else
+            local cb = timerPool[param]
+            --如果不是循环定时器,从定时器id表中删除此定时器
+            if exparam == 0 then timerPool[param] = nil end
+            if para[param] ~= nil then
+                cb(unpack(para[param]))
+                if exparam == 0 then para[param] = nil end
+            else
+                cb()
+            end
+            --如果是循环定时器,继续启动此定时器
+            --if loop[param] then rtos.timer_start(param, loop[param]) end
+        end
+    --其他消息(音频消息、充电管理消息、按键消息等)
+    --elseif type(msg) == "number" then
+    --    handlers[msg](param, exparam)
+    --else
+    --    handlers[msg.id](msg)
+    end
+end
+
+--- run()从底层获取core消息并及时处理相关消息,查询定时器并调度各注册成功的任务线程运行和挂起
+-- @return 无
+-- @usage sys.run()
+function sys.run()
+    --local result, err
+    while true do
+        --if sRollBack then
+            safeRun()
+        --else
+        --    result, err = pcall(safeRun)
+        --    if not result then rtos.restart(err) end
+        --end
+    end
+end
+
+_G.sys_pub = sys.publish
+
+return sys
+----------------------------

+ 2 - 9
bsp/win32/port/luat_base_win32.c

@@ -25,7 +25,7 @@ static const luaL_Reg loadedlibs[] = {
   {LUA_OSLIBNAME, luaopen_os},        // os库,已精简
   {LUA_STRLIBNAME, luaopen_string},   // string库,字符串操作
   {LUA_MATHLIBNAME, luaopen_math},    // math 数值计算
-//  {LUA_UTF8LIBNAME, luaopen_utf8},
+  {LUA_UTF8LIBNAME, luaopen_utf8},
   {LUA_DBLIBNAME, luaopen_debug},     // debug库,已精简
 #if defined(LUA_COMPAT_BITLIB)
   {LUA_BITLIBNAME, luaopen_bit32},    // 不太可能启用
@@ -39,22 +39,15 @@ static const luaL_Reg loadedlibs[] = {
   {"zbuff", luaopen_zbuff},            // 
 //   {"mqttcore", luaopen_mqttcore},      // 
 //   {"libcoap", luaopen_libcoap},        // 
-// #ifdef LUA_USE_WINDOWS
-//   {"lfs", luaopen_lfs},                //
-// //   {"rs232.core", luaopen_rs232_core},
-// #endif
   {"crypto", luaopen_crypto},
   {"fatfs", luaopen_fatfs},
   {"sfd",   luaopen_sfd},
   {"lfs2",   luaopen_lfs2},
   {"gpio",   luaopen_gpio},
+  {"luf",    luaopen_luf},
 #ifdef LUAT_USE_LVGL
   {"lvgl",   luaopen_lvgl},
-//   {"lcd",    luaopen_lcd},
 #endif
-// #ifdef LUAT_USE_LWIP
-//   {"lwip",   luaopen_lwip},
-// #endif
   {NULL, NULL}
 };
 

+ 2 - 2
components/luf/luat_luf_dump.c

@@ -288,8 +288,8 @@ int luf_dump(lua_State *L, const Proto *f, lua_Writer w, void *data,
 
   fd_offset = ptroffset + 1;
 
-  LLOGD("sizeof(Upvaldesc) %d", sizeof(Upvaldesc));
-  LLOGD("sizeof(LocVar) %d", sizeof(LocVar));
+  // LLOGD("sizeof(Upvaldesc) %d", sizeof(Upvaldesc));
+  // LLOGD("sizeof(LocVar) %d", sizeof(LocVar));
 
   DumpHeader(&D);
   DumpByte(f->sizeupvalues, &D);

+ 21 - 19
lua/src/lstrlib.c

@@ -178,26 +178,26 @@ static int str_char (lua_State *L) {
   return 1;
 }
 
+#if defined(LUA_USE_LINUX) || defined(LUA_USE_WINDOWS) || defined(LUA_USE_MACOSX)
+static int writer (lua_State *L, const void *b, size_t size, void *B) {
+  (void)L;
+  luaL_addlstring((luaL_Buffer *) B, (const char *)b, size);
+  return 0;
+}
 
-// static int writer (lua_State *L, const void *b, size_t size, void *B) {
-//   (void)L;
-//   luaL_addlstring((luaL_Buffer *) B, (const char *)b, size);
-//   return 0;
-// }
-
-
-// static int str_dump (lua_State *L) {
-//   luaL_Buffer b;
-//   int strip = lua_toboolean(L, 2);
-//   luaL_checktype(L, 1, LUA_TFUNCTION);
-//   lua_settop(L, 1);
-//   luaL_buffinit(L,&b);
-//   if (lua_dump(L, writer, &b, strip) != 0)
-//     return luaL_error(L, "unable to dump given function");
-//   luaL_pushresult(&b);
-//   return 1;
-// }
 
+static int str_dump (lua_State *L) {
+  luaL_Buffer b;
+  int strip = lua_toboolean(L, 2);
+  luaL_checktype(L, 1, LUA_TFUNCTION);
+  lua_settop(L, 1);
+  luaL_buffinit(L,&b);
+  if (lua_dump(L, writer, &b, strip) != 0)
+    return luaL_error(L, "unable to dump given function");
+  luaL_pushresult(&b);
+  return 1;
+}
+#endif
 
 
 /*
@@ -1549,7 +1549,9 @@ int l_str_fromBase64(lua_State *L);
 static const rotable_Reg strlib[] = {
   {"byte", str_byte, 0},
   {"char", str_char, 0},
-  //{"dump", str_dump, 0},
+#if defined(LUA_USE_LINUX) || defined(LUA_USE_WINDOWS) || defined(LUA_USE_MACOSX)
+  {"dump", str_dump, 0},
+#endif
   {"find", str_find, 0},
   {"format", str_format, 0},
   {"gmatch", gmatch, 0},