forked from hotdll/irtu-rda8955
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsys.lua
393 lines (363 loc) · 13.4 KB
/
sys.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
--- 模块功能:Luat协程调度框架
-- @module sys
-- @author openLuat
-- @license MIT
-- @copyright openLuat
-- @release 2017.9.13
require "utils"
require "log"
require "patch"
module(..., package.seeall)
-- lib脚本版本号,只要lib中的任何一个脚本做了修改,都需要更新此版本号
SCRIPT_LIB_VER = "2.3.3"
-- TaskID最大值
local TASK_TIMER_ID_MAX = 0x1FFFFFFF
-- msgId 最大值(请勿修改否则会发生msgId碰撞的危险)
local MSG_TIMER_ID_MAX = 0x7FFFFFFF
-- 任务定时器id
local taskTimerId = 0
-- 消息定时器id
local msgId = TASK_TIMER_ID_MAX
-- 定时器id表
local timerPool = {}
local taskTimerPool = {}
--消息定时器参数表
local para = {}
--定时器是否循环表
local loop = {}
--lua脚本运行出错时,是否回退为本地烧写的版本
local sRollBack = true
-- 启动GSM协议栈。例如在充电开机未启动GSM协议栈状态下,如果用户长按键正常开机,此时调用此接口启动GSM协议栈即可
-- @return 无
-- @usage sys.powerOn()
function powerOn()
rtos.poweron(1)
end
--- 软件重启
-- @string r 重启原因,用户自定义,一般是string类型,重启后的trace中会打印出此重启原因
-- @return 无
-- @usage sys.restart('程序超时软件重启')
function restart(r)
assert(r and r ~= "", "sys.restart cause null")
if errDump and errDump.appendErr and type(errDump.appendErr) == "function" then errDump.appendErr("restart[" .. r .. "];") end
rtos.restart()
end
--- Task任务延时函数,只能用于任务函数中
-- @number ms 整数,最大等待126322567毫秒
-- @return 定时结束返回nil,被其他线程唤起返回调用线程传入的参数
-- @usage sys.wait(30)
function wait(ms)
-- 参数检测,参数不能为负值
assert(ms > 0, "The wait time cannot be negative!")
-- 选一个未使用的定时器ID给该任务线程
if taskTimerId >= TASK_TIMER_ID_MAX then taskTimerId = 0 end
taskTimerId = taskTimerId + 1
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 waitUntil(id, ms)
subscribe(id, coroutine.running())
local message = ms and {wait(ms)} or {coroutine.yield()}
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 waitUntilExt(id, ms)
subscribe(id, coroutine.running())
local message = ms and {wait(ms)} or {coroutine.yield()}
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 taskInit(fun, ...)
local co = coroutine.create(fun)
coroutine.resume(co, unpack(arg))
return co
end
--- Luat平台初始化
-- @param mode 充电开机是否启动GSM协议栈,1不启动,否则启动
-- @param lprfnc 用户应用脚本中定义的“低电关机处理函数”,如果有函数名,则低电时,本文件中的run接口不会执行任何动作,否则,会延时1分钟自动关机
-- @return 无
-- @usage sys.init(1,0)
function init(mode, lprfnc)
-- 用户应用脚本中必须定义PROJECT和VERSION两个全局变量,否则会死机重启,如何定义请参考各个demo中的main.lua
assert(PROJECT and PROJECT ~= "" and VERSION and VERSION ~= "", "Undefine PROJECT or VERSION")
collectgarbage("setpause", 80)
-- 设置AT命令的虚拟串口
uart.setup(uart.ATC, 0, 0, uart.PAR_NONE, uart.STOP_1)
log.info("poweron reason:", rtos.poweron_reason(), PROJECT, VERSION, SCRIPT_LIB_VER, rtos.get_version())
if mode == 1 then
-- 充电开机
if rtos.poweron_reason() == rtos.POWERON_CHARGER then
-- 关闭GSM协议栈
rtos.poweron(0)
end
end
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 timerStop(val, ...)
-- val 为定时器ID
if type(val) == 'number' then
timerPool[val], para[val], loop[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(arg, para[k]) then
rtos.timer_stop(k)
timerPool[k], para[k], loop[val] = nil
break
end
end
end
end
end
--- 关闭同一回调函数的所有定时器
-- @param fnc 定时器回调函数
-- @return 无
-- @usage timerStopAll(cbFnc)
function 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], loop[k] = nil
end
end
end
--- 开启一个定时器
-- @param fnc 定时器回调函数
-- @number ms 整数,最大定时126322567毫秒
-- @param ... 可变参数 fnc的参数
-- @return number 定时器ID,如果失败,返回nil
function timerStart(fnc, ms, ...)
--回调函数和时长检测
assert(fnc ~= nil, "sys.timerStart(first param) is nil !")
assert(ms > 0, "sys.timerStart(Second parameter) is <= zero !")
-- 关闭完全相同的定时器
if arg.n == 0 then
timerStop(fnc)
else
timerStop(fnc, unpack(arg))
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) ~= 1 then log.debug("rtos.timer_start error") return end
--如果存在可变参数,在定时器参数表中保存参数
if arg.n ~= 0 then
para[msgId] = arg
end
--返回定时器id
return msgId
end
--- 开启一个循环定时器
-- @param fnc 定时器回调函数
-- @number ms 整数,最大定时126322567毫秒
-- @param ... 可变参数 fnc的参数
-- @return number 定时器ID,如果失败,返回nil
function timerLoopStart(fnc, ms, ...)
local tid = timerStart(fnc, ms, unpack(arg))
if tid then loop[tid] = ms end
return tid
end
--- 判断某个定时器是否处于开启状态
-- @param val 有两种形式
--一种是开启定时器时返回的定时器id,此形式时不需要再传入可变参数...就能唯一标记一个定时器
--另一种是开启定时器时的回调函数,此形式时必须再传入可变参数...才能唯一标记一个定时器
-- @param ... 可变参数
-- @return number 开启状态返回true,否则nil
function timerIsActive(val, ...)
if type(val) == "number" then
return timerPool[val]
else
for k, v in pairs(timerPool) do
if v == val then
if cmpTable(arg, 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 subscribe(id, callback)
if type(id) ~= "string" or (type(callback) ~= "function" and type(callback) ~= "thread") then
log.warn("warning: sys.subscribe invalid parameter", id, callback)
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 unsubscribe(id, callback)
if type(id) ~= "string" or (type(callback) ~= "function" and type(callback) ~= "thread") then
log.warn("warning: sys.unsubscribe invalid parameter", id, callback)
return
end
if subscribers[id] then subscribers[id][callback] = nil end
end
--- 发布内部消息,存储在内部消息队列中
-- @param ... 可变参数,用户自定义
-- @return 无
-- @usage publish("NET_STATUS_IND")
function publish(...)
table.insert(messageQueue, arg)
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
coroutine.resume(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)
rtos.on = function(id, handler)
handlers[id] = handler
end
------------------------------------------ Luat 主调度框架 ------------------------------------------
local function safeRun()
-- 分发内部消息
dispatch()
-- 阻塞读取外部消息
local msg, param, exparam = rtos.receive(rtos.INF_TIMEOUT)
-- 判断是否为定时器消息,并且消息是否注册
if 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
coroutine.resume(taskId)
end
else
local cb = timerPool[param]
--如果不是循环定时器,从定时器id表中删除此定时器
if not loop[param] then timerPool[param] = nil end
if para[param] ~= nil then
cb(unpack(para[param]))
if not loop[param] 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 run()
local result, err
while true do
if sRollBack then
safeRun()
else
result, err = pcall(safeRun)
if not result then restart(err) end
end
end
end
--- 设置“lua脚本运行出错时,是否回退原始烧写版本”的功能开关。如果没有调用此接口设置,默认回滚
-- @bool flag,“lua脚本运行出错时,是否回退原始烧写版本”的标志,true表示回滚,false表示不回滚
-- @return nil
-- @usage
-- sys.setRollBack(true)
-- sys.setRollBack(false)
function setRollBack(flag)
sRollBack = flag
end
require "clib"