luat_lib_rtos.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  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. -- 读取底层位数, 32或者64, 2025.12.23 新增
  241. local luatos_version, luatos_version_num, luatos_bits = rtos.version(true)
  242. */
  243. static int l_rtos_version(lua_State *L) {
  244. lua_pushstring(L, luat_version_str());
  245. // 当多传入一个参数时,且值为true,则返回数字版本号
  246. if (lua_isboolean(L, 1) && lua_toboolean(L, 1)) {
  247. #ifdef LUAT_CONF_FIRMWARE_TYPE_NUM
  248. lua_pushinteger(L, LUAT_CONF_FIRMWARE_TYPE_NUM);
  249. #else
  250. lua_pushinteger(L, 0);
  251. #endif
  252. #ifdef LUAT_CONF_VM_64bit
  253. lua_pushinteger(L, 64);
  254. #else
  255. lua_pushinteger(L, 32);
  256. #endif
  257. return 3;
  258. }
  259. return 1;
  260. }
  261. /*
  262. 进入待机模式, 仅部分设备可用, 本API已废弃, 推荐使用pm库
  263. @api rtos.standy(timeout)
  264. @int 休眠时长,单位毫秒
  265. @return nil 无返回值
  266. @usage
  267. -- 进入待机模式
  268. rtos.standby(5000)
  269. */
  270. static int l_rtos_standy(lua_State *L) {
  271. int timeout = luaL_checkinteger(L, 1);
  272. luat_os_standy(timeout);
  273. return 0;
  274. }
  275. /*
  276. 获取内存信息
  277. @api rtos.meminfo(type)
  278. @type "sys"系统内存, "lua"虚拟机内存,"psram"psram内存, 默认为lua虚拟机内存
  279. @return int 总内存大小,单位字节
  280. @return int 当前已使用的内存大小,单位字节
  281. @return int 历史最高已使用的内存大小,单位字节
  282. @usage
  283. -- 打印内存占用
  284. log.info("mem.lua", rtos.meminfo())
  285. log.info("mem.sys", rtos.meminfo("sys"))
  286. */
  287. static int l_rtos_meminfo(lua_State *L) {
  288. size_t len = 0;
  289. size_t total = 0;
  290. size_t used = 0;
  291. size_t max_used = 0;
  292. const char * str = luaL_optlstring(L, 1, "lua", &len);
  293. if (strcmp("sys", str) == 0) {
  294. #ifdef LUAT_USE_MEM_LOGOUT
  295. luat_meminfo_query(LUAT_HEAP_SRAM, &total, &used, &max_used, 1);
  296. #else
  297. luat_meminfo_opt_sys(LUAT_HEAP_SRAM, &total, &used, &max_used);
  298. #endif
  299. }
  300. else if(strcmp("psram", str) == 0){
  301. #ifdef LUAT_USE_MEM_LOGOUT
  302. luat_meminfo_query(LUAT_HEAP_PSRAM, &total, &used, &max_used, 1);
  303. #else
  304. luat_meminfo_opt_sys(LUAT_HEAP_PSRAM, &total, &used, &max_used);
  305. #endif
  306. }
  307. else {
  308. #ifdef LUAT_USE_MEM_LOGOUT
  309. luat_meminfo_query(0, &total, &used, &max_used, 1);
  310. #else
  311. luat_meminfo_luavm(&total, &used, &max_used);
  312. #endif
  313. }
  314. lua_pushinteger(L, total);
  315. lua_pushinteger(L, used);
  316. lua_pushinteger(L, max_used);
  317. return 3;
  318. }
  319. /*
  320. 返回底层描述信息,格式为 LuatOS_$VERSION_$BSP,可用于OTA升级判断底层信息
  321. @api rtos.firmware()
  322. @return string 底层描述信息
  323. @usage
  324. -- 打印底层描述信息
  325. log.info("firmware", rtos.firmware())
  326. */
  327. static int l_rtos_firmware(lua_State *L) {
  328. lua_pushfstring(L, "LuatOS-SoC_%s_%s", luat_version_str(), luat_os_bsp());
  329. return 1;
  330. }
  331. extern char custom_search_paths[4][24];
  332. /*
  333. 设置自定义lua脚本搜索路径,优先级高于内置路径
  334. @api rtos.setPaths(pathA, pathB, pathC, pathD)
  335. @string 路径A, 例如 "/sdcard/%s.luac",若不传值,将默认为"",另外,最大长度不能超过23字节
  336. @string 路径B, 例如 "/sdcard/%s.lua"
  337. @string 路径C, 例如 "/lfs2/%s.luac"
  338. @string 路径D, 例如 "/lfs2/%s.lua"
  339. @usage
  340. -- 挂载sd卡或者spiflash后
  341. rtos.setPaths("/sdcard/user/%s.luac", "/sdcard/user/%s.lua")
  342. require("sd_user_main") -- 将搜索并加载 /sdcard/user/sd_user_main.luac 和 /sdcard/user/sd_user_main.lua
  343. */
  344. static int l_rtos_set_paths(lua_State *L) {
  345. size_t len = 0;
  346. const char* str = NULL;
  347. for (size_t i = 0; i < 4; i++)
  348. {
  349. if (lua_isstring(L, i +1)) {
  350. str = luaL_checklstring(L, i+1, &len);
  351. memcpy(custom_search_paths[i], str, len + 1);
  352. }
  353. else {
  354. custom_search_paths[i][0] = 0x00;
  355. }
  356. }
  357. return 0;
  358. }
  359. /*
  360. 空函数,什么都不做
  361. @api rtos.nop()
  362. @return nil 无返回值
  363. @usage
  364. -- 这个函数单纯就是 lua -> c -> lua 走一遍
  365. -- 没有参数,没有返回值,没有逻辑处理
  366. -- 在绝大多数情况下,不会遇到这个函数的调用
  367. -- 它通常只会出现在性能测试的代码里, 因为它什么都不干.
  368. rtos.nop()
  369. */
  370. static int l_rtos_nop(lua_State *L) {
  371. (void)L;
  372. return 0;
  373. }
  374. /*
  375. 内存自动收集配置,是lua本身收集机制的一种补充,不是必要的,而且只在luavm空闲时触发
  376. @api rtos.autoCollectMem(period, warning_level, force_level)
  377. @int 自动收集的周期,等同于receive调用次数,0~60000。如果是0,则关闭自动收集功能,默认是100
  378. @int 内存使用警戒水位线,是总luavm内存量的百分比,50~95,内存达到(>=)警戒线时才会开始判断是否要收集。默认是80
  379. @int 内存使用强制收集水位线,是总luavm内存量的百分比,50~95,内存达到(>=)强制收集线时会强制收集。默认是90,必须比警戒水位线大
  380. @return nil 无返回值
  381. @usage
  382. rtos.autoCollectMem(100, 80, 90)
  383. */
  384. static int l_rtos_auto_colloect_mem(lua_State *L) {
  385. uint32_t period = luaL_optinteger(L, 1, 100);
  386. uint32_t mid = luaL_optinteger(L, 2, 80);
  387. uint32_t high = luaL_optinteger(L, 3, 90);
  388. if (period > 60000) {
  389. return 0;
  390. }
  391. if (mid > 95 || high > 95) {
  392. return 0;
  393. }
  394. if (mid < 50 || high < 50) {
  395. return 0;
  396. }
  397. if (mid >= high) {
  398. return 0;
  399. }
  400. LLOGD("mem collect param %u,%u,%u -> %u,%u,%u", autogc_config, autogc_mid_water, autogc_high_water, period, mid, high);
  401. autogc_config = period;
  402. autogc_mid_water = mid;
  403. autogc_high_water = high;
  404. return 0;
  405. }
  406. // TODO 部分平台不支持LUAT_WEAK
  407. LUAT_WEAK int luat_poweron_reason(void) {
  408. return 0;
  409. }
  410. //uint32_t-高16位重启主原因,低16位详细原因
  411. //高16位:0-上电/复位开机,1-用户主动软件重启,2-RTC开机,3-异常重启,4-唤醒开机
  412. //低16位
  413. //
  414. // static int l_rtos_poweron_reason(lua_State *L) {
  415. // lua_pushinteger(L,luat_poweron_reason());
  416. // return 1;
  417. // }
  418. //------------------------------------------------------------------
  419. #include "rotable2.h"
  420. static const rotable_Reg_t reg_rtos[] =
  421. {
  422. { "timer_start" , ROREG_FUNC(l_rtos_timer_start)},
  423. { "timer_stop", ROREG_FUNC(l_rtos_timer_stop)},
  424. { "receive", ROREG_FUNC(l_rtos_receive)},
  425. { "reboot", ROREG_FUNC(l_rtos_reboot)},
  426. // { "poweron_reason", ROREG_FUNC(l_rtos_poweron_reason)},
  427. { "standy", ROREG_FUNC(l_rtos_standy)},
  428. { "buildDate", ROREG_FUNC(l_rtos_build_date)},
  429. { "bsp", ROREG_FUNC(l_rtos_bsp)},
  430. { "version", ROREG_FUNC(l_rtos_version)},
  431. { "meminfo", ROREG_FUNC(l_rtos_meminfo)},
  432. { "firmware", ROREG_FUNC(l_rtos_firmware)},
  433. { "setPaths", ROREG_FUNC(l_rtos_set_paths)},
  434. { "nop", ROREG_FUNC(l_rtos_nop)},
  435. { "autoCollectMem", ROREG_FUNC(l_rtos_auto_colloect_mem)},
  436. { "INF_TIMEOUT", ROREG_INT(-1)},
  437. { "MSG_TIMER", ROREG_INT(MSG_TIMER)},
  438. // { "MSG_GPIO", NULL, MSG_GPIO},
  439. // { "MSG_UART_RX", NULL, MSG_UART_RX},
  440. // { "MSG_UART_TXDONE", NULL, MSG_UART_TXDONE},
  441. { NULL, ROREG_INT(0) }
  442. };
  443. LUAMOD_API int luaopen_rtos( lua_State *L ) {
  444. luat_newlib2(L, reg_rtos);
  445. return 1;
  446. }
  447. LUAT_WEAK const char* luat_version_str(void) {
  448. #ifdef LUAT_BSP_VERSION
  449. return LUAT_BSP_VERSION;
  450. #else
  451. return LUAT_VERSION;
  452. #endif
  453. }