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