1 /*
2 * Copyright (C) 2018-2020 Alibaba Group Holding Limited
3 */
4
5 #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_GLP)
6 #include <stdio.h>
7 #include <string.h>
8 #include <ctype.h>
9 //#include <aos/aos.h>
10 #include <aos/kernel.h>
11 #include <hal/hal.h>
12 #include <aos/hal/gpio.h>
13 #include <genie_sal_lpm.h>
14 #include <genie_lpm.h>
15
16 #if defined(BOARD_TG7100B)
17 #include "pm.h"
18 #endif
19
20 #include "common/log.h"
21 #include "genie_service.h"
22
23 static genie_lpm_ctx_t genie_lpm_ctx;
24
25 #ifndef GENIE_WAKE_UP_IO_NUM_MAX
26 #define GENIE_WAKE_UP_IO_NUM_MAX 5
27 #endif
28
29 genie_lpm_wakeup_io_config_t g_wakeup_io[GENIE_WAKE_UP_IO_NUM_MAX];
30
31 static uint8_t g_wakeup_io_num = 0;
32
33 #ifndef CONFIG_GENIE_MESH_ENABLE_SLEEP_WHEN_NOT_PROV
34 #define CONFIG_GENIE_MESH_ENABLE_SLEEP_WHEN_NOT_PROV 0
35 #endif
36
_genie_lpm_timer_irq_handler(void * p_timer,void * args)37 static void _genie_lpm_timer_irq_handler(void *p_timer, void *args)
38 {
39 int ret = 0;
40
41 BT_DBG("[%u]cur status: %d\n", k_uptime_get_32(), genie_lpm_ctx.status);
42
43 if (genie_lpm_ctx.has_disabled == 1)
44 {
45 BT_DBG("lpm already disable, stop timer\n");
46 aos_timer_stop(&genie_lpm_ctx.wakeup_timer);
47 return;
48 }
49
50 if (STATUS_WAKEUP == genie_lpm_ctx.status)
51 {
52 BT_DBG("[%u]sleep and suspend mesh stack\n", k_uptime_get_32());
53 ret = genie_mesh_suspend(false);
54 if (0 == ret || -EALREADY == ret)
55 {
56 genie_lpm_ctx.status = STATUS_SLEEP;
57 if (!genie_lpm_ctx.p_config.genie_lpm_cb)
58 {
59 genie_lpm_ctx.p_config.genie_lpm_cb(WAKEUP_BY_TIMER, genie_lpm_ctx.status, NULL);
60 }
61 aos_timer_stop(&genie_lpm_ctx.wakeup_timer);
62 aos_timer_change(&genie_lpm_ctx.wakeup_timer, genie_lpm_ctx.p_config.sleep_ms);
63 aos_timer_start(&genie_lpm_ctx.wakeup_timer);
64 }
65 else
66 {
67 aos_timer_stop(&genie_lpm_ctx.wakeup_timer);
68 aos_timer_change(&genie_lpm_ctx.wakeup_timer, genie_lpm_ctx.p_config.wakeup_ms);
69 aos_timer_start(&genie_lpm_ctx.wakeup_timer);
70 }
71 }
72 else if (STATUS_SLEEP == genie_lpm_ctx.status)
73 {
74 BT_DBG("[%u]wake up and resume mesh stack\n", k_uptime_get_32());
75 ret = genie_mesh_resume();
76 if (0 == ret || -EALREADY == ret)
77 {
78 genie_lpm_ctx.status = STATUS_WAKEUP;
79 genie_lpm_ctx.p_config.genie_lpm_cb(WAKEUP_BY_TIMER, genie_lpm_ctx.status, NULL);
80 aos_timer_stop(&genie_lpm_ctx.wakeup_timer);
81 aos_timer_change(&genie_lpm_ctx.wakeup_timer, genie_lpm_ctx.p_config.wakeup_ms);
82 aos_timer_start(&genie_lpm_ctx.wakeup_timer);
83 }
84 else
85 {
86 aos_timer_stop(&genie_lpm_ctx.wakeup_timer);
87 aos_timer_change(&genie_lpm_ctx.wakeup_timer, genie_lpm_ctx.p_config.sleep_ms);
88 aos_timer_start(&genie_lpm_ctx.wakeup_timer);
89 }
90 }
91 }
92 /*
93 static void _genie_lpm_io_wakeup_timer_irq_handler(void *p_timer, void *args)
94 {
95 int ret = 0;
96
97 BT_DBG("[%u]wakeup by i/o\n", k_uptime_get_32());
98 aos_timer_stop(&genie_lpm_ctx.io_wakeup_timer);
99
100 BT_DBG("[%u]cur status: %d\n", k_uptime_get_32(), genie_lpm_ctx.status);
101 if (STATUS_SLEEP == genie_lpm_ctx.status)
102 {
103 BT_DBG("[%u]wake up and resume mesh stack\n", k_uptime_get_32());
104 ret = genie_mesh_resume();
105 if (0 == ret)
106 {
107 genie_lpm_ctx.status = STATUS_WAKEUP;
108 genie_lpm_ctx.p_config.genie_lpm_cb(WAKEUP_BY_IO, genie_lpm_ctx.status);
109 }
110 }
111 else
112 {
113 genie_lpm_ctx.p_config.genie_lpm_cb(WAKEUP_IS_WAKEUP, genie_lpm_ctx.status);
114 }
115 }*/
116
genie_lpm_io_wakeup_handler(void * arg)117 __attribute__((section(".__sram.code"))) void genie_lpm_io_wakeup_handler(void *arg)
118 {
119 if (genie_lpm_ctx.p_config.lpm_wakeup_io != 0)
120 {
121 uint8_t trigger_found = 0;
122 _genie_lpm_io_status_t g_io_status[GENIE_WAKE_UP_IO_NUM_MAX];
123 long long interrupt_time = aos_now_ms();
124
125 if ((interrupt_time - genie_lpm_ctx.last_interrupt_time < INTERRUPT_DELAY_TIME))
126 {
127 return; //for debounce
128 }
129
130 genie_lpm_ctx.last_interrupt_time = interrupt_time;
131
132 for (int i = 0; i < g_wakeup_io_num; i++)
133 {
134 bool status = genie_sal_sleep_wakeup_io_get_status(g_wakeup_io[i].port);
135 if (((g_wakeup_io[i].io_pol == FALLING || g_wakeup_io[i].io_pol == ACT_LOW) && status == false) || ((g_wakeup_io[i].io_pol == RISING || g_wakeup_io[i].io_pol == ACT_HIGH) && status == true))
136 {
137 g_io_status[i].port = g_wakeup_io[i].port;
138 g_io_status[i].trigger_flag = 1;
139 g_io_status[i].status = status;
140 trigger_found = 1;
141 }
142 }
143
144 if (trigger_found)
145 {
146 BT_DBG("[%u]wakeup by i/o\n", k_uptime_get_32());
147 BT_DBG("[%u]cur status: %d\n", k_uptime_get_32(), genie_lpm_ctx.status);
148 if (STATUS_SLEEP == genie_lpm_ctx.status)
149 {
150 int ret = 0;
151 BT_DBG("[%u]wake up and resume mesh stack\n", k_uptime_get_32());
152 ret = genie_mesh_resume();
153 if (0 == ret)
154 {
155 genie_lpm_ctx.status = STATUS_WAKEUP;
156 _genie_lpm_io_status_list_t list;
157 list.size = g_wakeup_io_num;
158 list.io_status = g_io_status;
159 genie_lpm_ctx.p_config.genie_lpm_cb(WAKEUP_BY_IO, genie_lpm_ctx.status, &list);
160 }
161 }
162 else
163 {
164 genie_lpm_ctx.p_config.genie_lpm_cb(WAKEUP_IS_WAKEUP, genie_lpm_ctx.status, NULL);
165 }
166 }
167 }
168 }
169
_genie_lpm_io_wakeup_init(genie_lpm_wakeup_io_t config)170 static void _genie_lpm_io_wakeup_init(genie_lpm_wakeup_io_t config)
171 {
172 if (config.io_list_size > GENIE_WAKE_UP_IO_NUM_MAX)
173 {
174 GENIE_LOG_ERR("Wakeup i/o num should no more than %d", GENIE_WAKE_UP_IO_NUM_MAX);
175 }
176 g_wakeup_io_num = GENIE_WAKE_UP_IO_NUM_MAX < config.io_list_size ? GENIE_WAKE_UP_IO_NUM_MAX : config.io_list_size;
177 memcpy(g_wakeup_io, config.io_config, sizeof(genie_lpm_wakeup_io_config_t) * g_wakeup_io_num);
178
179 for (int i = 0; i < g_wakeup_io_num; i++)
180 {
181 genie_sal_sleep_wakup_io_set(g_wakeup_io[i].port, g_wakeup_io[i].io_pol);
182 }
183
184 genie_sal_io_wakeup_cb_register(genie_lpm_io_wakeup_handler);
185 }
186
187 /*
188 static void _genie_lpm_io_wakeup_timer_init(void)
189 {
190 aos_timer_new(&genie_lpm_ctx.io_wakeup_timer, _genie_lpm_io_wakeup_timer_irq_handler, NULL, 10, 0);
191 aos_timer_stop(&genie_lpm_ctx.io_wakeup_timer);
192 }*/
193
_genie_lpm_wakeup_timer_init(void)194 static void _genie_lpm_wakeup_timer_init(void)
195 {
196 aos_timer_new(&genie_lpm_ctx.wakeup_timer, _genie_lpm_timer_irq_handler, NULL, genie_lpm_ctx.p_config.delay_sleep_time, 0);
197 aos_timer_stop(&genie_lpm_ctx.wakeup_timer);
198 }
199
genie_lpm_disable(void)200 int genie_lpm_disable(void)
201 {
202 GENIE_LOG_INFO("lpm disable");
203
204 if (genie_lpm_ctx.is_mesh_init == 1)
205 {
206 genie_mesh_resume();
207 }
208
209 genie_lpm_ctx.has_disabled = 1;
210 genie_lpm_ctx.status = STATUS_WAKEUP;
211 aos_timer_stop(&genie_lpm_ctx.wakeup_timer);
212 genie_sal_sleep_disable();
213
214 return 0;
215 }
216
genie_lpm_enable(bool force)217 int genie_lpm_enable(bool force)
218 {
219 GENIE_LOG_INFO("lpm enable");
220
221 if (genie_lpm_ctx.is_mesh_init == 1)
222 {
223 genie_mesh_suspend(force);
224 }
225
226 genie_lpm_ctx.has_disabled = 0;
227 genie_sal_sleep_enable();
228 genie_lpm_ctx.status = STATUS_SLEEP;
229
230 if (force)
231 {
232 aos_timer_stop(&genie_lpm_ctx.wakeup_timer);
233 }
234 else
235 {
236 aos_timer_stop(&genie_lpm_ctx.wakeup_timer);
237 aos_timer_change(&genie_lpm_ctx.wakeup_timer, genie_lpm_ctx.p_config.sleep_ms);
238 aos_timer_start(&genie_lpm_ctx.wakeup_timer);
239 }
240
241 return 0;
242 }
243
genie_lpm_deep_sleep(void)244 int genie_lpm_deep_sleep(void)
245 {
246 *(volatile uint32_t *)PWR_BOOT_REASON = PWR_STANDBY_BOOT_FLAG;
247 return genie_sal_sleep_enter_standby();
248 }
249
genie_lpm_init(genie_lpm_conf_t * lpm_conf)250 void genie_lpm_init(genie_lpm_conf_t *lpm_conf)
251 {
252 uint32_t *p_boot_reason = (uint32_t *)PWR_BOOT_REASON;
253
254 memcpy(&genie_lpm_ctx.p_config, lpm_conf, sizeof(genie_lpm_conf_t));
255
256 if (genie_lpm_ctx.p_config.genie_lpm_cb == NULL)
257 {
258 GENIE_LOG_ERR("lpm param err");
259 return;
260 }
261
262 if (genie_lpm_ctx.p_config.delay_sleep_time == 0)
263 {
264 genie_lpm_ctx.p_config.delay_sleep_time = DEFAULT_BOOTUP_DELAY_SLEEP_TIME;
265 }
266
267 genie_lpm_ctx.status = STATUS_WAKEUP;
268
269 GENIE_LOG_INFO("io_wakeup:%d, sleep:%dms, wakeup:%dms, after:%dms", genie_lpm_ctx.p_config.lpm_wakeup_io, genie_lpm_ctx.p_config.sleep_ms, genie_lpm_ctx.p_config.wakeup_ms, genie_lpm_ctx.p_config.delay_sleep_time);
270 if (genie_lpm_ctx.p_config.lpm_wakeup_io != 0 && genie_lpm_ctx.p_config.lpm_wakeup_io_config.io_list_size != 0)
271 {
272 _genie_lpm_io_wakeup_init(lpm_conf->lpm_wakeup_io_config);
273 //_genie_lpm_io_wakeup_timer_init(); //Do things in the timer when wakeup by IO
274 }
275
276 if ((genie_lpm_ctx.p_config.sleep_ms != 0) && (genie_lpm_ctx.p_config.wakeup_ms != 0))
277 {
278 _genie_lpm_wakeup_timer_init();
279 }
280
281 #if !(CONFIG_GENIE_MESH_ENABLE_SLEEP_WHEN_NOT_PROV)
282 genie_sal_sleep_disable();
283 #endif
284
285 if (*p_boot_reason == PWR_STANDBY_BOOT_FLAG)
286 {
287 GENIE_LOG_INFO("standy boot flag");
288 *(volatile uint32_t *)PWR_BOOT_REASON = 0;
289 }
290 }
291
genie_lpm_start(void)292 int genie_lpm_start(void)
293 {
294 genie_lpm_ctx.is_mesh_init = 1;
295 BT_DBG("genie lpm mesh ready");
296 if (genie_lpm_ctx.p_config.is_auto_enable == 1)
297 {
298 genie_lpm_ctx.has_disabled = 0;
299 genie_sal_sleep_enable();
300 genie_lpm_ctx.status = STATUS_SLEEP;
301 aos_timer_stop(&genie_lpm_ctx.wakeup_timer);
302 aos_timer_start(&genie_lpm_ctx.wakeup_timer);
303 }
304 else
305 {
306 if (genie_lpm_ctx.p_config.delay_sleep_time > 0)
307 {
308 genie_lpm_ctx.has_disabled = 0;
309 aos_timer_start(&genie_lpm_ctx.wakeup_timer);
310 }
311 }
312
313 return 0;
314 }
315