luat_lib_rtos.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. /*
  2. @module rtos
  3. @summary RTOS底层操作库
  4. @version 1.0
  5. @date 2020.03.30
  6. @tag LUAT_USE_GPIO
  7. */
  8. #include "luat_base.h"
  9. #include "luat_sys.h"
  10. #include "luat_msgbus.h"
  11. #include "luat_timer.h"
  12. #include "luat_mem.h"
  13. #define LUAT_LOG_TAG "rtos"
  14. #include "luat_log.h"
  15. static uint32_t autogc_high_water = 90;
  16. static uint32_t autogc_mid_water = 80;
  17. static uint16_t autogc_config = 100; // TODO 通过API可配置
  18. static uint16_t autogc_counter = 0;
  19. #ifndef LUAT_COMPILER_NOWEAK
  20. LUAT_WEAK uint8_t luat_msgbus_is_empty(void)
  21. {
  22. return 0;
  23. }
  24. #endif
  25. /*
  26. 接受并处理底层消息队列.
  27. @api rtos.receive(timeout)
  28. @int 超时时长,通常是-1,永久等待
  29. @return msgid 如果是定时器消息,会返回定时器消息id及附加信息, 其他消息由底层决定,不向lua层进行任何保证.
  30. -- 本方法通过sys.run()调用, 普通用户不要使用
  31. rtos.receive(-1)
  32. */
  33. static int l_rtos_receive(lua_State *L) {
  34. rtos_msg_t msg = {0};
  35. int re = {0};
  36. size_t total = 0;
  37. size_t used = 0;
  38. size_t max_used = 0;
  39. //系统空闲且设置了自动收集功能
  40. if (luat_msgbus_is_empty() && autogc_config)
  41. {
  42. //LLOGD("auto collect check %d,%d", luat_msgbus_is_empty(), autogc_config);
  43. luat_meminfo_luavm(&total, &used, &max_used);
  44. //达到强制线就直接收集了
  45. if ( (used * 100) >= (total * autogc_high_water))
  46. {
  47. //LLOGD("luavm ram too high! used %d, total %d. Trigger Force-GC", used, total);
  48. // 需要执行2次, 因为userdata在第二次才会被回收
  49. lua_gc(L, LUA_GCCOLLECT, 0);
  50. lua_gc(L, LUA_GCCOLLECT, 0);
  51. }
  52. else
  53. {
  54. if (autogc_counter >= autogc_config) {
  55. autogc_counter = 0;
  56. if ( (used * 100) >= (total * autogc_mid_water))
  57. {
  58. //LLOGD("luavm ram too high! used %d, total %d. Trigger Force-GC", used, total);
  59. // 需要执行2次, 因为userdata在第二次才会被回收
  60. lua_gc(L, LUA_GCCOLLECT, 0);
  61. lua_gc(L, LUA_GCCOLLECT, 0);
  62. }
  63. }
  64. else {
  65. autogc_counter ++;
  66. }
  67. }
  68. }
  69. else
  70. {
  71. autogc_counter = 0; //这里也许可以不清零
  72. }
  73. re = luat_msgbus_get(&msg, luaL_checkinteger(L, 1));
  74. if (!re) {
  75. //LLOGD("rtos_msg got, invoke it handler=%08X", msg.handler);
  76. lua_pushlightuserdata(L, (void*)(&msg));
  77. return msg.handler(L, msg.ptr);
  78. }
  79. else {
  80. //LLOGD("rtos_msg get timeout");
  81. lua_pushinteger(L, -1);
  82. return 1;
  83. }
  84. }
  85. //------------------------------------------------------------------
  86. static int l_timer_handler(lua_State *L, void* ptr) {
  87. rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
  88. luat_timer_t *timer = (luat_timer_t *)ptr;
  89. int timer_id = msg->arg1;
  90. if (timer_id > 0) {
  91. timer = luat_timer_get(timer_id);
  92. }
  93. else if (timer != NULL) {
  94. timer_id = timer->id;
  95. timer = luat_timer_get(timer_id);
  96. }
  97. if (timer == NULL)
  98. return 0;
  99. // LLOGD("l_timer_handler id=%ld\n", timer->id);
  100. lua_pushinteger(L, MSG_TIMER);
  101. lua_pushinteger(L, timer->id);
  102. lua_pushinteger(L, timer->repeat);
  103. //lua_pushinteger(L, timer->timeout);
  104. if (timer->repeat == 0) {
  105. // LLOGD("stop timer %d", timer_id);
  106. luat_timer_stop(timer);
  107. luat_heap_free(timer);
  108. }
  109. else if (timer->repeat > 0) {
  110. timer->repeat --;
  111. }
  112. return 3;
  113. }
  114. /*
  115. 启动一个定时器
  116. @api rtos.timer_start(id,timeout,_repeat)
  117. @int 定时器id
  118. @int 超时时长,单位毫秒
  119. @int 重复次数,默认是0
  120. @return id 如果是定时器消息,会返回定时器消息id及附加信息, 其他消息由底层决定,不向lua层进行任何保证.
  121. @usage
  122. -- 用户代码请使用 sys.timerStart
  123. -- 启动一个3秒的循环定时器
  124. rtos.timer_start(10000, 3000, -1)
  125. */
  126. static int l_rtos_timer_start(lua_State *L) {
  127. lua_gettop(L);
  128. size_t timeout = 0;
  129. size_t type = 0;
  130. size_t id = (size_t)luaL_checkinteger(L, 1) / 1;
  131. #if 0
  132. if (lua_isnumber(L, 2)) {
  133. timeout = lua_tonumber(L, 2) * 1000;
  134. type = 1;
  135. } else
  136. #endif
  137. timeout = (size_t)luaL_checkinteger(L, 2);
  138. int repeat = (size_t)luaL_optinteger(L, 3, 0);
  139. // LLOGD("start timer id=%ld", id);
  140. // LLOGD("timer timeout=%ld", timeout);
  141. // LLOGD("timer repeat=%ld", repeat);
  142. if (timeout < 1) {
  143. lua_pushinteger(L, 0);
  144. return 1;
  145. }
  146. luat_timer_t *timer = (luat_timer_t*)luat_heap_malloc(sizeof(luat_timer_t));
  147. if (timer == NULL){
  148. LLOGE("timer malloc fail");
  149. lua_pushinteger(L, 0);
  150. return 1;
  151. }
  152. timer->id = id;
  153. timer->timeout = timeout;
  154. timer->repeat = repeat;
  155. timer->func = &l_timer_handler;
  156. timer->type = type;
  157. int re = luat_timer_start(timer);
  158. if (re == 0) {
  159. lua_pushinteger(L, 1);
  160. }
  161. else {
  162. LLOGD("start timer fail, free timer %p", timer);
  163. luat_heap_free(timer);
  164. lua_pushinteger(L, 0);
  165. }
  166. return 1;
  167. }
  168. /*
  169. 关闭并释放一个定时器
  170. @api rtos.timer_stop(id)
  171. @int 定时器id
  172. @return nil 无返回值
  173. @usage
  174. -- 用户代码请使用sys.timerStop
  175. rtos.timer_stop(id)
  176. */
  177. static int l_rtos_timer_stop(lua_State *L) {
  178. int timerid = -1;
  179. luat_timer_t *timer = NULL;
  180. if (!lua_isinteger(L, 1)) {
  181. return 0;
  182. }
  183. timerid = lua_tointeger(L, 1);
  184. timer = luat_timer_get(timerid);
  185. if (timer != NULL) {
  186. // LLOGD("timer stop, free timer %d", timerid);
  187. luat_timer_stop(timer);
  188. luat_heap_free(timer);
  189. }
  190. return 0;
  191. }
  192. /*
  193. 设备重启
  194. @api rtos.reboot()
  195. @return nil 无返回值
  196. -- 立即重启设备
  197. rtos.reboot()
  198. */
  199. int l_rtos_reboot(lua_State *L) {
  200. luat_os_reboot(luaL_optinteger(L, 1, 0));
  201. return 0;
  202. }
  203. //-----------------------------------------------------------------
  204. /*
  205. 获取固件编译日期
  206. @api rtos.buildDate()
  207. @return string 固件编译日期
  208. @usage
  209. -- 获取编译日期
  210. local d = rtos.buildDate()
  211. */
  212. static int l_rtos_build_date(lua_State *L) {
  213. lua_pushstring(L, __DATE__);
  214. return 1;
  215. }
  216. /*
  217. 获取硬件bsp型号
  218. @api rtos.bsp()
  219. @return string 硬件bsp型号
  220. @usage
  221. -- 获取硬件bsp型号
  222. local bsp = rtos.bsp()
  223. */
  224. static int l_rtos_bsp(lua_State *L) {
  225. lua_pushstring(L, luat_os_bsp());
  226. return 1;
  227. }
  228. /*
  229. 获取固件版本号
  230. @api rtos.version(more)
  231. @int more 可选参数,默认不传. 传入true时,会额外返回数字版本号
  232. @return string 固件版本号,例如"V0001"
  233. @usage
  234. -- 读取版本号
  235. local luatos_version = rtos.version()
  236. -- 读取版本号及数字版本号, 2025.11.1之后的固件支持
  237. -- 如果不是数字固件,luatos_version_num 会是0
  238. -- 如果是不支持的固件, luatos_version_num 会是nil
  239. local luatos_version, luatos_version_num = rtos.version(true)
  240. */
  241. static int l_rtos_version(lua_State *L) {
  242. lua_pushstring(L, luat_version_str());
  243. // 当多传入一个参数时,且值为true,则返回数字版本号
  244. if (lua_isboolean(L, 1) && lua_toboolean(L, 1)) {
  245. #ifdef LUAT_CONF_FIRMWARE_TYPE_NUM
  246. lua_pushinteger(L, LUAT_CONF_FIRMWARE_TYPE_NUM);
  247. #else
  248. lua_pushinteger(L, 0);
  249. #endif
  250. return 2;
  251. }
  252. return 1;
  253. }
  254. /*
  255. 进入待机模式, 仅部分设备可用, 本API已废弃, 推荐使用pm库
  256. @api rtos.standy(timeout)
  257. @int 休眠时长,单位毫秒
  258. @return nil 无返回值
  259. @usage
  260. -- 进入待机模式
  261. rtos.standby(5000)
  262. */
  263. static int l_rtos_standy(lua_State *L) {
  264. int timeout = luaL_checkinteger(L, 1);
  265. luat_os_standy(timeout);
  266. return 0;
  267. }
  268. /*
  269. 获取内存信息
  270. @api rtos.meminfo(type)
  271. @type "sys"系统内存, "lua"虚拟机内存,"psram"psram内存, 默认为lua虚拟机内存
  272. @return int 总内存大小,单位字节
  273. @return int 当前已使用的内存大小,单位字节
  274. @return int 历史最高已使用的内存大小,单位字节
  275. @usage
  276. -- 打印内存占用
  277. log.info("mem.lua", rtos.meminfo())
  278. log.info("mem.sys", rtos.meminfo("sys"))
  279. */
  280. static int l_rtos_meminfo(lua_State *L) {
  281. size_t len = 0;
  282. size_t total = 0;
  283. size_t used = 0;
  284. size_t max_used = 0;
  285. const char * str = luaL_optlstring(L, 1, "lua", &len);
  286. if (strcmp("sys", str) == 0) {
  287. luat_meminfo_opt_sys(LUAT_HEAP_SRAM, &total, &used, &max_used);
  288. }
  289. else if(strcmp("psram", str) == 0){
  290. luat_meminfo_opt_sys(LUAT_HEAP_PSRAM, &total, &used, &max_used);
  291. }
  292. else {
  293. luat_meminfo_luavm(&total, &used, &max_used);
  294. }
  295. lua_pushinteger(L, total);
  296. lua_pushinteger(L, used);
  297. lua_pushinteger(L, max_used);
  298. return 3;
  299. }
  300. /*
  301. 返回底层描述信息,格式为 LuatOS_$VERSION_$BSP,可用于OTA升级判断底层信息
  302. @api rtos.firmware()
  303. @return string 底层描述信息
  304. @usage
  305. -- 打印底层描述信息
  306. log.info("firmware", rtos.firmware())
  307. */
  308. static int l_rtos_firmware(lua_State *L) {
  309. lua_pushfstring(L, "LuatOS-SoC_%s_%s", luat_version_str(), luat_os_bsp());
  310. return 1;
  311. }
  312. extern char custom_search_paths[4][24];
  313. /*
  314. 设置自定义lua脚本搜索路径,优先级高于内置路径
  315. @api rtos.setPaths(pathA, pathB, pathC, pathD)
  316. @string 路径A, 例如 "/sdcard/%s.luac",若不传值,将默认为"",另外,最大长度不能超过23字节
  317. @string 路径B, 例如 "/sdcard/%s.lua"
  318. @string 路径C, 例如 "/lfs2/%s.luac"
  319. @string 路径D, 例如 "/lfs2/%s.lua"
  320. @usage
  321. -- 挂载sd卡或者spiflash后
  322. rtos.setPaths("/sdcard/user/%s.luac", "/sdcard/user/%s.lua")
  323. require("sd_user_main") -- 将搜索并加载 /sdcard/user/sd_user_main.luac 和 /sdcard/user/sd_user_main.lua
  324. */
  325. static int l_rtos_set_paths(lua_State *L) {
  326. size_t len = 0;
  327. const char* str = NULL;
  328. for (size_t i = 0; i < 4; i++)
  329. {
  330. if (lua_isstring(L, i +1)) {
  331. str = luaL_checklstring(L, i+1, &len);
  332. memcpy(custom_search_paths[i], str, len + 1);
  333. }
  334. else {
  335. custom_search_paths[i][0] = 0x00;
  336. }
  337. }
  338. return 0;
  339. }
  340. /*
  341. 空函数,什么都不做
  342. @api rtos.nop()
  343. @return nil 无返回值
  344. @usage
  345. -- 这个函数单纯就是 lua -> c -> lua 走一遍
  346. -- 没有参数,没有返回值,没有逻辑处理
  347. -- 在绝大多数情况下,不会遇到这个函数的调用
  348. -- 它通常只会出现在性能测试的代码里, 因为它什么都不干.
  349. rtos.nop()
  350. */
  351. static int l_rtos_nop(lua_State *L) {
  352. (void)L;
  353. return 0;
  354. }
  355. /*
  356. 内存自动收集配置,是lua本身收集机制的一种补充,不是必要的,而且只在luavm空闲时触发
  357. @api rtos.autoCollectMem(period, warning_level, force_level)
  358. @int 自动收集的周期,等同于receive调用次数,0~60000。如果是0,则关闭自动收集功能,默认是100
  359. @int 内存使用警戒水位线,是总luavm内存量的百分比,50~95,内存达到(>=)警戒线时才会开始判断是否要收集。默认是80
  360. @int 内存使用强制收集水位线,是总luavm内存量的百分比,50~95,内存达到(>=)强制收集线时会强制收集。默认是90,必须比警戒水位线大
  361. @return nil 无返回值
  362. @usage
  363. rtos.autoCollectMem(100, 80, 90)
  364. */
  365. static int l_rtos_auto_colloect_mem(lua_State *L) {
  366. uint32_t period = luaL_optinteger(L, 1, 100);
  367. uint32_t mid = luaL_optinteger(L, 2, 80);
  368. uint32_t high = luaL_optinteger(L, 3, 90);
  369. if (period > 60000) {
  370. return 0;
  371. }
  372. if (mid > 95 || high > 95) {
  373. return 0;
  374. }
  375. if (mid < 50 || high < 50) {
  376. return 0;
  377. }
  378. if (mid >= high) {
  379. return 0;
  380. }
  381. LLOGD("mem collect param %u,%u,%u -> %u,%u,%u", autogc_config, autogc_mid_water, autogc_high_water, period, mid, high);
  382. autogc_config = period;
  383. autogc_mid_water = mid;
  384. autogc_high_water = high;
  385. return 0;
  386. }
  387. // TODO 部分平台不支持LUAT_WEAK
  388. LUAT_WEAK int luat_poweron_reason(void) {
  389. return 0;
  390. }
  391. //uint32_t-高16位重启主原因,低16位详细原因
  392. //高16位:0-上电/复位开机,1-用户主动软件重启,2-RTC开机,3-异常重启,4-唤醒开机
  393. //低16位
  394. //
  395. // static int l_rtos_poweron_reason(lua_State *L) {
  396. // lua_pushinteger(L,luat_poweron_reason());
  397. // return 1;
  398. // }
  399. //------------------------------------------------------------------
  400. #include "rotable2.h"
  401. static const rotable_Reg_t reg_rtos[] =
  402. {
  403. { "timer_start" , ROREG_FUNC(l_rtos_timer_start)},
  404. { "timer_stop", ROREG_FUNC(l_rtos_timer_stop)},
  405. { "receive", ROREG_FUNC(l_rtos_receive)},
  406. { "reboot", ROREG_FUNC(l_rtos_reboot)},
  407. // { "poweron_reason", ROREG_FUNC(l_rtos_poweron_reason)},
  408. { "standy", ROREG_FUNC(l_rtos_standy)},
  409. { "buildDate", ROREG_FUNC(l_rtos_build_date)},
  410. { "bsp", ROREG_FUNC(l_rtos_bsp)},
  411. { "version", ROREG_FUNC(l_rtos_version)},
  412. { "meminfo", ROREG_FUNC(l_rtos_meminfo)},
  413. { "firmware", ROREG_FUNC(l_rtos_firmware)},
  414. { "setPaths", ROREG_FUNC(l_rtos_set_paths)},
  415. { "nop", ROREG_FUNC(l_rtos_nop)},
  416. { "autoCollectMem", ROREG_FUNC(l_rtos_auto_colloect_mem)},
  417. { "INF_TIMEOUT", ROREG_INT(-1)},
  418. { "MSG_TIMER", ROREG_INT(MSG_TIMER)},
  419. // { "MSG_GPIO", NULL, MSG_GPIO},
  420. // { "MSG_UART_RX", NULL, MSG_UART_RX},
  421. // { "MSG_UART_TXDONE", NULL, MSG_UART_TXDONE},
  422. { NULL, ROREG_INT(0) }
  423. };
  424. LUAMOD_API int luaopen_rtos( lua_State *L ) {
  425. luat_newlib2(L, reg_rtos);
  426. return 1;
  427. }
  428. LUAT_WEAK const char* luat_version_str(void) {
  429. #ifdef LUAT_BSP_VERSION
  430. return LUAT_BSP_VERSION;
  431. #else
  432. return LUAT_VERSION;
  433. #endif
  434. }