luat_lib_pm.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. /*
  2. @module pm
  3. @summary 电源管理
  4. @version 1.0
  5. @date 2020.07.02
  6. @demo pm
  7. @tag LUAT_USE_PM
  8. @usage
  9. --[[
  10. 休眠模式简介
  11. -- IDLE 正常运行模式
  12. -- LIGHT 轻睡眠模式:
  13. CPU暂停
  14. RAM保持供电
  15. 定时器/网络事件/IO中断均可自动唤醒
  16. 唤醒后程序继续运行
  17. GPIO保持电平
  18. -- DEEP 深睡眠模式
  19. CPU暂停
  20. 核心RAM掉电, 保留RAM维持供电
  21. 普通GPIO掉电,外设驱动掉电
  22. AON_GPIO保持休眠前的电平
  23. dtimer定时器可唤醒
  24. wakeup脚可唤醒
  25. 唤醒后程序从头运行,休眠前的运行时数据全丢
  26. -- HIB 休眠模式
  27. CPU暂停
  28. RAM掉电, 保留RAM也掉电
  29. 普通GPIO掉电,外设驱动掉电
  30. AON_GPIO保持休眠前的电平
  31. dtimer定时器可唤醒
  32. wakeup脚可唤醒
  33. 唤醒后程序从头运行,休眠前的运行时数据全丢
  34. 对部分模块,例如Air780E, DEEP/HIB对用户代码没有区别
  35. 除pm.shutdown()外, RTC总是运行的, 除非掉电
  36. ]]
  37. -- 定时器唤醒, 请使用 pm.dtimerStart()
  38. -- wakeup唤醒
  39. -- 如Air101/Air103, 有独立的wakeup脚, 不需要配置,可直接控制唤醒
  40. -- 如Air780E系列, 有多个wakeup可用, 通过gpio.setup(32)配置虚拟GPIO进行唤醒配置
  41. pm.request(pm.IDLE) -- 通过切换不同的值请求进入不同的休眠模式
  42. -- 对应Air780E系列, 执行后并不一定马上进入休眠模式, 如无后续数据传输需求,可先进入飞行模式,然后快速休眠
  43. */
  44. #include "lua.h"
  45. #include "lauxlib.h"
  46. #include "luat_base.h"
  47. #include "luat_pm.h"
  48. #include "luat_msgbus.h"
  49. #define LUAT_LOG_TAG "pm"
  50. #include "luat_log.h"
  51. // static int lua_event_cb = 0;
  52. /**
  53. 请求进入指定的休眠模式
  54. @api pm.request(mode)
  55. @int 休眠模式,例如pm.IDLE/LIGHT/DEEP/HIB.
  56. @return boolean 处理结果,即使返回成功,也不一定会进入, 也不会马上进入
  57. @usage
  58. -- 请求进入休眠模式
  59. --[[
  60. IDLE 正常运行,就是无休眠
  61. LIGHT 轻休眠, CPU停止, RAM保持, 外设保持, 可中断唤醒. 部分型号支持从休眠处继续运行
  62. DEEP 深休眠, CPU停止, RAM掉电, 仅特殊引脚保持的休眠前的电平, 大部分管脚不能唤醒设备.
  63. HIB 彻底休眠, CPU停止, RAM掉电, 仅复位/特殊唤醒管脚可唤醒设备.
  64. ]]
  65. pm.request(pm.HIB)
  66. */
  67. static int l_pm_request(lua_State *L) {
  68. int mode = luaL_checkinteger(L, 1);
  69. if (luat_pm_request(mode) == 0)
  70. lua_pushboolean(L, 1);
  71. else
  72. lua_pushboolean(L, 0);
  73. return 1;
  74. }
  75. // static int l_pm_release(lua_State *L) {
  76. // int mode = luaL_checkinteger(L, 1);
  77. // if (luat_pm_release(mode) == 0)
  78. // lua_pushboolean(L, 1);
  79. // else
  80. // lua_pushboolean(L, 0);
  81. // return 1;
  82. // }
  83. /**
  84. 启动底层定时器,在休眠模式下依然生效. 只触发一次
  85. @api pm.dtimerStart(id, timeout)
  86. @int 定时器id,通常是0-3
  87. @int 定时时长,单位毫秒
  88. @return boolean 处理结果
  89. @usage
  90. -- 添加底层定时器
  91. pm.dtimerStart(0, 300 * 1000) -- 5分钟后唤醒
  92. */
  93. static int l_pm_dtimer_start(lua_State *L) {
  94. int dtimer_id = luaL_checkinteger(L, 1);
  95. int timeout = luaL_checkinteger(L, 2);
  96. if (luat_pm_dtimer_start(dtimer_id, timeout)) {
  97. lua_pushboolean(L, 0);
  98. }
  99. else {
  100. lua_pushboolean(L, 1);
  101. }
  102. return 1;
  103. }
  104. /**
  105. 关闭底层定时器
  106. @api pm.dtimerStop(id)
  107. @int 定时器id
  108. @usage
  109. -- 关闭底层定时器
  110. pm.dtimerStop(0) -- 关闭id=0的底层定时器
  111. */
  112. static int l_pm_dtimer_stop(lua_State *L) {
  113. int dtimer_id = luaL_checkinteger(L, 1);
  114. luat_pm_dtimer_stop(dtimer_id);
  115. return 0;
  116. }
  117. /**
  118. 检查底层定时器是不是在运行
  119. @api pm.dtimerCheck(id)
  120. @int 定时器id
  121. @return boolean 处理结果,true还在运行,false不在运行
  122. @usage
  123. -- 检查底层定时器是不是在运行
  124. pm.dtimerCheck(0) -- 检查id=0的底层定时器
  125. */
  126. static int l_pm_dtimer_check(lua_State *L) {
  127. int dtimer_id = luaL_checkinteger(L, 1);
  128. if (luat_pm_dtimer_check(dtimer_id))
  129. {
  130. lua_pushboolean(L, 1);
  131. }
  132. else
  133. {
  134. lua_pushboolean(L, 0);
  135. }
  136. return 1;
  137. }
  138. static int l_pm_dtimer_list(lua_State *L) {
  139. size_t c = 0;
  140. size_t dlist[24];
  141. luat_pm_dtimer_list(&c, dlist);
  142. lua_createtable(L, c, 0);
  143. for (size_t i = 0; i < c; i++)
  144. {
  145. if (dlist[i] > 0) {
  146. lua_pushinteger(L, dlist[i]);
  147. lua_seti(L, -3, i+1);
  148. }
  149. }
  150. return 1;
  151. }
  152. static int l_pm_dtimer_wakeup_id(lua_State *L) {
  153. int dtimer_id = 0xFF;
  154. luat_pm_dtimer_wakeup_id(&dtimer_id);
  155. if (dtimer_id != 0xFF) {
  156. lua_pushinteger(L, dtimer_id);
  157. }
  158. else {
  159. lua_pushinteger(L, -1);
  160. }
  161. return 1;
  162. }
  163. // static int l_pm_on(lua_State *L) {
  164. // if (lua_isfunction(L, 1)) {
  165. // if (lua_event_cb != 0) {
  166. // luaL_unref(L, LUA_REGISTRYINDEX, lua_event_cb);
  167. // }
  168. // lua_event_cb = luaL_ref(L, LUA_REGISTRYINDEX);
  169. // }
  170. // else if (lua_event_cb != 0) {
  171. // luaL_unref(L, LUA_REGISTRYINDEX, lua_event_cb);
  172. // }
  173. // return 0;
  174. // }
  175. /**
  176. 开机原因,用于判断是从休眠模块开机,还是电源/复位开机
  177. @api pm.lastReson()
  178. @return int 0-上电/复位开机, 1-RTC开机, 2-WakeupIn/Pad/IO开机, 3-Wakeup/RTC开机
  179. @return int 0-普通开机(上电/复位),3-深睡眠开机,4-休眠开机
  180. @return int 复位开机详细原因:0-powerkey或者上电开机 1-充电或者AT指令下载完成后开机 2-闹钟开机 3-软件重启 4-未知原因 5-RESET键 6-异常重启 7-工具控制重启 8-内部看门狗重启 9-外部重启 10-充电开机
  181. @usage
  182. -- 是哪种方式开机呢
  183. log.info("pm", "last power reson", pm.lastReson())
  184. */
  185. static int l_pm_last_reson(lua_State *L) {
  186. int lastState = 0;
  187. int rtcOrPad = 0;
  188. luat_pm_last_state(&lastState, &rtcOrPad);
  189. lua_pushinteger(L, rtcOrPad);
  190. lua_pushinteger(L, lastState);
  191. lua_pushinteger(L, luat_pm_get_poweron_reason());
  192. return 3;
  193. }
  194. /**
  195. 强制进入指定的休眠模式,忽略某些外设的影响,比如USB
  196. @api pm.force(mode)
  197. @int 休眠模式
  198. @return boolean 处理结果,若返回成功,大概率会马上进入该休眠模式
  199. @usage
  200. -- 请求进入休眠模式
  201. pm.force(pm.HIB)
  202. */
  203. static int l_pm_force(lua_State *L) {
  204. lua_pushinteger(L, luat_pm_force(luaL_checkinteger(L, 1)));
  205. return 1;
  206. }
  207. /**
  208. 检查休眠状态
  209. @api pm.check()
  210. @return boolean 处理结果,如果能顺利进入休眠,返回true,否则返回false
  211. @return int 底层返回值,0代表能进入最底层休眠,其他值代表最低可休眠级别
  212. @usage
  213. -- 请求进入休眠模式,然后检查是否能真的休眠
  214. pm.request(pm.HIB)
  215. if pm.check() then
  216. log.info("pm", "it is ok to hib")
  217. else
  218. pm.force(pm.HIB) -- 强制休眠
  219. end
  220. */
  221. static int l_pm_check(lua_State *L) {
  222. int ret = luat_pm_check();
  223. lua_pushboolean(L, luat_pm_check() == 0 ? 1 : 0);
  224. lua_pushinteger(L, ret);
  225. return 2;
  226. }
  227. #ifndef LUAT_COMPILER_NOWEAK
  228. LUAT_WEAK int luat_pm_poweroff(void) {
  229. LLOGW("powerOff is not supported");
  230. return -1;
  231. }
  232. #else
  233. extern int luat_pm_poweroff(void);
  234. #endif
  235. /**
  236. 关机
  237. @api pm.shutdown()
  238. @return nil 无返回值
  239. @usage
  240. -- 当前仅EC618系列(Air780E/Air600E/Air700E/Air780EG支持)
  241. -- 需要2022-12-22之后编译的固件
  242. pm.shutdown()
  243. */
  244. static int l_pm_power_off(lua_State *L) {
  245. (void)L;
  246. luat_pm_poweroff();
  247. return 0;
  248. }
  249. /**
  250. 重启
  251. @api pm.reboot()
  252. @return nil 无返回值
  253. -- 立即重启设备, 本函数的行为与rtos.reboot()完全一致,只是在pm库做个别名
  254. pm.reboot()
  255. */
  256. int l_rtos_reboot(lua_State *L);
  257. int l_rtos_standby(lua_State *L);
  258. /**
  259. 开启内部的电源控制,注意不是所有的平台都支持,可能部分平台支持部分选项,看硬件
  260. @api pm.power(id, onoff)
  261. @int 电源控制id,pm.USB pm.GPS之类
  262. @boolean 开关true开,false关,默认关. 部分选项支持数值
  263. @return boolean 处理结果true成功,false失败
  264. @usage
  265. -- 关闭USB电源, 反之开启就是传true
  266. pm.power(pm.USB, false)
  267. -- Air780EG,为内置的GPS芯片上电. 注意, Air780EG的GPS和GPS_ANT是一起控制的,所以合并了.
  268. pm.power(pm.GPS, true)
  269. -- EC618系列开启pwrkey开机防抖
  270. -- 注意: 开启后, 复位键就变成关机了!!! pwrkey要长按2秒才能开机
  271. -- pm.power(pm.PWK_MODE, true)
  272. -- EC618系列设置IO电平, 范围 1650 ~ 3400 , 单位毫伏, 步进50mv
  273. -- 注意, 这里的设置优先级会高于硬件IOSEL脚的配置
  274. -- pm.power(pm.IOVLOT_GPIO, 3300)
  275. -- pm.power(pm.IOVLOT_AONGPIO, 3300)
  276. */
  277. static int l_pm_power_ctrl(lua_State *L) {
  278. uint8_t onoff = 0;
  279. int id = luaL_checkinteger(L, 1);
  280. if (lua_isboolean(L, 2)) {
  281. onoff = lua_toboolean(L, 2);
  282. }
  283. lua_pushboolean(L, !luat_pm_power_ctrl(id, onoff));
  284. return 1;
  285. }
  286. /**
  287. IO高电平电压控制,当前仅EC618系列可用
  288. @api pm.ioVol(id, val)
  289. @int 电平id,目前只有pm.IOVOL_ALL_GPIO
  290. @int 电平值,单位毫伏
  291. @return boolean 处理结果true成功,false失败
  292. @usage
  293. -- EC618系列设置IO电平, 范围 1650 ~ 2000,2650~3400 , 单位毫伏, 步进50mv
  294. -- 例如Air780E/Air600E/Air700E/Air780EG
  295. -- 注意, 这里的设置优先级会高于硬件IOSEL脚的配置
  296. -- 但开机时依然先使用硬件配置,直至调用本API进行配置, 所以io电平会变化
  297. -- pm.ioVol(pm.IOVOL_ALL_GPIO, 3300) -- 所有GPIO高电平输出3.3V
  298. -- pm.ioVol(pm.IOVOL_ALL_GPIO, 1800) -- 所有GPIO高电平输出1.8V
  299. */
  300. static int l_pm_iovolt_ctrl(lua_State *L) {
  301. int val = 3300;
  302. int id = luaL_checkinteger(L, LUAT_PM_ALL_GPIO);
  303. if (lua_isboolean(L, 2)) {
  304. val = lua_toboolean(L, 2);
  305. }
  306. else if (lua_isinteger(L, 2)) {
  307. val = luaL_checkinteger(L, 2);
  308. }
  309. lua_pushboolean(L, !luat_pm_iovolt_ctrl(id, val));
  310. return 1;
  311. }
  312. #ifndef LUAT_COMPILER_NOWEAK
  313. LUAT_WEAK int luat_pm_iovolt_ctrl(int id, int val) {
  314. return -1;
  315. }
  316. #endif
  317. /**
  318. 配置唤醒引脚 (当前仅仅esp系列可用)
  319. @api pm.wakeupPin(pin,level)
  320. @int/table gpio引脚
  321. @int 唤醒电压 可选,默认低电平唤醒
  322. @return boolean 处理结果
  323. @usage
  324. pm.wakeupPin(8,0)
  325. */
  326. static int l_pm_wakeup_pin(lua_State *L) {
  327. int level = luaL_optinteger(L, 2,0);
  328. if (lua_istable(L, 1)) {
  329. size_t count = lua_rawlen(L, 1);
  330. for (size_t i = 1; i <= count; i++){
  331. lua_geti(L, 1, i);
  332. luat_pm_wakeup_pin(luaL_checkinteger(L, -1), level);
  333. lua_pop(L, 1);
  334. }
  335. }else if(lua_isnumber(L, 1)){
  336. luat_pm_wakeup_pin(luaL_checkinteger(L, 1), level);
  337. }
  338. lua_pushboolean(L, 1);
  339. return 1;
  340. }
  341. #include "rotable2.h"
  342. static const rotable_Reg_t reg_pm[] =
  343. {
  344. { "request" , ROREG_FUNC(l_pm_request )},
  345. // { "release" , ROREG_FUNC( l_pm_release)},
  346. { "dtimerStart", ROREG_FUNC(l_pm_dtimer_start)},
  347. { "dtimerStop" , ROREG_FUNC(l_pm_dtimer_stop)},
  348. { "dtimerCheck" , ROREG_FUNC(l_pm_dtimer_check)},
  349. { "dtimerList", ROREG_FUNC(l_pm_dtimer_list)},
  350. { "dtimerWkId", ROREG_FUNC(l_pm_dtimer_wakeup_id)},
  351. //{ "on", ROREG_FUNC(l_pm_on)},
  352. { "force", ROREG_FUNC(l_pm_force)},
  353. { "check", ROREG_FUNC(l_pm_check)},
  354. { "lastReson", ROREG_FUNC(l_pm_last_reson)},
  355. { "shutdown", ROREG_FUNC(l_pm_power_off)},
  356. { "reboot", ROREG_FUNC(l_rtos_reboot)},
  357. { "power", ROREG_FUNC(l_pm_power_ctrl)},
  358. { "ioVol", ROREG_FUNC(l_pm_iovolt_ctrl)},
  359. { "wakeupPin", ROREG_FUNC(l_pm_wakeup_pin)},
  360. //@const NONE number 不休眠模式
  361. { "NONE", ROREG_INT(LUAT_PM_SLEEP_MODE_NONE)},
  362. //@const IDLE number IDLE模式
  363. { "IDLE", ROREG_INT(LUAT_PM_SLEEP_MODE_IDLE)},
  364. //@const LIGHT number LIGHT模式
  365. { "LIGHT", ROREG_INT(LUAT_PM_SLEEP_MODE_LIGHT)},
  366. //@const DEEP number DEEP模式
  367. { "DEEP", ROREG_INT(LUAT_PM_SLEEP_MODE_DEEP)},
  368. //@const HIB number HIB模式
  369. { "HIB", ROREG_INT(LUAT_PM_SLEEP_MODE_STANDBY)},
  370. //@const USB number USB电源
  371. { "USB", ROREG_INT(LUAT_PM_POWER_USB)},
  372. //@const GPS number GPS电源
  373. { "GPS", ROREG_INT(LUAT_PM_POWER_GPS)},
  374. //@const GPS_ANT number GPS的天线电源,有源天线才需要
  375. { "GPS_ANT", ROREG_INT(LUAT_PM_POWER_GPS_ANT)},
  376. //@const CAMERA number camera电源,CAM_VCC输出
  377. { "CAMERA", ROREG_INT(LUAT_PM_POWER_CAMERA)},
  378. //@const DAC_EN number Air780E和Air600E的DAC_EN,注意audio的默认配置会自动使用这个脚来控制CODEC的使能
  379. { "DAC_EN", ROREG_INT(LUAT_PM_POWER_DAC_EN_PIN)},
  380. //@const PWK_MODE number 是否开启ec618的powerkey滤波模式,true开,注意滤波模式下reset变成直接关机
  381. { "PWK_MODE", ROREG_INT(LUAT_PM_POWER_POWERKEY_MODE)},
  382. //@const IOVL 所有GPIO高电平电压控制,当前仅ec618系列可用
  383. { "IOVOL_ALL_GPIO", ROREG_INT(LUAT_PM_ALL_GPIO)},
  384. { NULL, ROREG_INT(0) }
  385. };
  386. LUAMOD_API int luaopen_pm( lua_State *L ) {
  387. luat_newlib2(L, reg_pm);
  388. return 1;
  389. }