• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  *****************************************************************************************
3  *
4  * @file app_timer.c
5  *
6  * @brief app timer function Implementation.
7  *
8  *****************************************************************************************
9  * @attention
10   #####Copyright (c) 2019 GOODIX
11   All rights reserved.
12 
13     Redistribution and use in source and binary forms, with or without
14     modification, are permitted provided that the following conditions are met:
15   * Redistributions of source code must retain the above copyright
16     notice, this list of conditions and the following disclaimer.
17   * Redistributions in binary form must reproduce the above copyright
18     notice, this list of conditions and the following disclaimer in the
19     documentation and/or other materials provided with the distribution.
20   * Neither the name of GOODIX nor the names of its contributors may be used
21     to endorse or promote products derived from this software without
22     specific prior written permission.
23 
24   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27   ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
28   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34   POSSIBILITY OF SUCH DAMAGE.
35  *****************************************************************************************
36  */
37 
38 /*
39  * INCLUDE FILES
40  *****************************************************************************************
41  */
42 #include <stdio.h>
43 #include "custom_config.h"
44 #include "gr55xx_hal.h"
45 #include "gr55xx_pwr.h"
46 #include "app_timer.h"
47 
48 #if APP_TIMER_USE_SCHEDULER
49 #include "app_scheduler.h"
50 #endif
51 
52 /*
53  * DEFINES
54  *****************************************************************************************
55  */
56 /*
57   ------------------------------------------------------------------------------
58   | PRIGROUP | BIT INFO  | GROUP PRI BITS | SUBPRI BITS | GROUP PRIS | SUBPRIS |
59   ------------------------------------------------------------------------------
60   |  0B011   | xxxx.yyyy |      [7:4]     |    [3:0]    |     16     |    16   |
61   ------------------------------------------------------------------------------
62   Note :
63   App timer uses the basepri feature to implement the lock, in which the lock will
64   not disable SVC_IRQ, BLE_IRQ, BLE_SLEEP_IRQ to ensure the highest priority of
65   Bluetooth services
66 */
67 #define LOCAL_APP_TIMER_LOCK()                                  \
68     do {                                                         \
69         uint32_t __l_irq_rest = __get_BASEPRI();                 \
70         __set_BASEPRI(NVIC_GetPriority(BLE_IRQn) +               \
71                      (1 << (NVIC_GetPriorityGrouping() + 1)));   \
72     } while (0)
73 
74 #define LOCAL_APP_TIMER_UNLOCK()                                \
75     do {                                                         \
76         uint32_t __l_irq_rest = __get_BASEPRI(); \
77         __set_BASEPRI(__l_irq_rest); \
78     } while (0)
79 
80 /**@brief The length of timer node list. */
81 #define TIMER_NODE_CNT                 20
82 #define TIMER_INVALID_DELAY_VALUE      0
83 #define TIMER_INVALID_NODE_NUMBER      0xFF
84 #define APP_TIMER_STOP_VALUE           0x1
85 #define APP_TIMER_INVALID_ID           NULL
86 #define APP_TIMER_SUC                  0x0
87 #define APP_TIMER_FAIL                 (-1)
88 #define APP_TIMER_LOCK()               LOCAL_APP_TIMER_LOCK()
89 #define APP_TIMER_UNLOCK()             LOCAL_APP_TIMER_UNLOCK()
90 
APP_TIMER_MS_TO_US(uint32_t x)91 static inline uint32_t APP_TIMER_MS_TO_US(uint32_t x)
92 {
93     return x * 1000UL;
94 }
95 
APP_TIMER_TICKS_TO_US(uint32_t x)96 static inline float APP_TIMER_TICKS_TO_US(uint32_t x)
97 {
98     float ret = ((x) * 1000000.0f / sys_lpclk_get());
99     return ret;
100 }
101 
APP_TIMER_GET_CURRENT_TICKS(uint32_t x)102 static inline void APP_TIMER_GET_CURRENT_TICKS(uint32_t x)
103 {
104     hal_pwr_get_timer_current_value(PWR_TIMER_TYPE_SLP_TIMER, x);
105 }
106 
107 /**@brief App timer global state variable. */
108 typedef struct app_timer_struct {
109     uint8_t                   apptimer_start;
110     uint8_t                   apptimer_in_int;
111     app_timer_t               *p_curr_timer_node;
112     int                       apptimer_runout_time;
113     uint32_t                  apptimer_total_ticks;
114     uint32_t                  apptimer_total_ticks_us;
115 } app_timer_info_t;
116 
117 
118 /**@brief App timer state types. */
119 enum {
120     APP_TIMER_STOP = 0,
121     APP_TIMER_START,
122 };
123 
124 /**@brief App timer state types. */
125 enum {
126     TIMER_NODE_FREE = 0,
127     TIMER_NODE_USED,
128 };
129 
130 /**@brief App timer state types. */
131 enum {
132     APP_TIMER_NODE_START = 0xaa,
133     APP_TIMER_NODE_STOP,
134 };
135 
136 /**@brief Aon-timer global list, all newly added timer nodes will be added to the queue. */
137 static app_timer_t      s_timer_node[TIMER_NODE_CNT];
138 static app_timer_info_t s_app_timer_info;
139 
140 /*
141  * LOCAL VARIABLE DEFINITIONS
142  *****************************************************************************************
143  */
get_next_timer(void)144 app_timer_t* get_next_timer(void)
145 {
146     int min_handle = TIMER_INVALID_NODE_NUMBER;
147     uint32_t min_value = (uint32_t)0xFFFFFFFF;
148 
149     for (int idx = 0; idx < TIMER_NODE_CNT; idx++) {
150         if (s_timer_node[idx].original_delay && (s_timer_node[idx].timer_node_status == APP_TIMER_NODE_START)) {
151             if ((s_timer_node[idx].next_trigger_time - s_app_timer_info.apptimer_total_ticks) < min_value) {
152                 min_value = s_timer_node[idx].next_trigger_time - s_app_timer_info.apptimer_total_ticks;
153                 min_handle = idx;
154             } else if (s_timer_node[idx].next_trigger_time < s_app_timer_info.apptimer_total_ticks) {
155                 s_timer_node[idx].next_trigger_time = s_app_timer_info.apptimer_total_ticks;
156                 min_value = 0;
157                 min_handle = idx;
158             }
159 
160             if (min_value == 0) {
161                 return &s_timer_node[min_handle];
162             }
163         }
164     }
165 
166     if (min_handle == TIMER_INVALID_NODE_NUMBER) {
167         return NULL;
168     }
169 
170     return &s_timer_node[min_handle];
171 }
172 
clear_total_ticks(void)173 void clear_total_ticks(void)
174 {
175     if (s_app_timer_info.apptimer_total_ticks >= 0xF0000000) {
176         for (int idx = 0; idx < TIMER_NODE_CNT; idx++) {
177             if (s_timer_node[idx].original_delay) {
178                 s_timer_node[idx].next_trigger_time -= s_app_timer_info.apptimer_total_ticks;
179             }
180         }
181         s_app_timer_info.apptimer_total_ticks = 0x0;
182     }
183 }
184 
app_timer_drv_stop(void)185 __STATIC_INLINE void app_timer_drv_stop(void)
186 {
187     hal_pwr_config_timer_wakeup(PWR_SLP_TIMER_MODE_DISABLE, APP_TIMER_STOP_VALUE);
188 }
189 
app_timer_get_valid_node(void)190 uint8_t app_timer_get_valid_node(void)
191 {
192     uint8_t idx = 0;
193     for (idx=0; idx<TIMER_NODE_CNT; idx ++) {
194         if (TIMER_NODE_FREE == s_timer_node[idx].timer_node_used) {
195             s_timer_node[idx].timer_node_used = TIMER_NODE_USED;
196             return idx;
197         }
198     }
199     return TIMER_INVALID_NODE_NUMBER;
200 }
201 
app_timer_set_var(uint8_t handle,uint8_t atimer_mode,app_timer_fun_t callback)202 void app_timer_set_var(uint8_t handle, uint8_t atimer_mode, app_timer_fun_t callback)
203 {
204     s_timer_node[handle].next_trigger_callback = callback;
205     s_timer_node[handle].next_trigger_mode = atimer_mode;
206 }
207 
208 
209 #if APP_TIMER_USE_SCHEDULER
timeout_handler_scheduled_exec(void * p_evt_data,uint16_t evt_size)210 static void timeout_handler_scheduled_exec(void * p_evt_data, uint16_t evt_size)
211 {
212     app_timer_evt_t const *p_timer_evt = (app_timer_evt_t *)p_evt_data;
213 
214     p_timer_evt->timeout_handler(p_timer_evt->p_ctx);
215 }
216 #endif
217 
hal_pwr_sleep_timer_elapsed_callback(void)218 TINY_RAM_SECTION void hal_pwr_sleep_timer_elapsed_callback(void)
219 {
220     APP_TIMER_LOCK();
221 
222     app_timer_t *p_timer_node = s_app_timer_info.p_curr_timer_node;
223     app_timer_t *p_exe_node = p_timer_node;
224     s_app_timer_info.apptimer_total_ticks += s_app_timer_info.apptimer_runout_time;
225 
226     if (p_timer_node->next_trigger_mode == ATIMER_ONE_SHOT) {
227         p_timer_node->original_delay = 0x0;
228     } else if (p_timer_node->next_trigger_mode == ATIMER_REPEAT) {
229         p_timer_node->next_trigger_time = p_timer_node->original_delay + s_app_timer_info.apptimer_total_ticks;
230     }
231 
232     clear_total_ticks();
233     s_app_timer_info.p_curr_timer_node = get_next_timer();
234     p_timer_node = s_app_timer_info.p_curr_timer_node;
235 
236     if (s_app_timer_info.p_curr_timer_node != NULL) {
237         s_app_timer_info.apptimer_runout_time = p_timer_node->next_trigger_time-s_app_timer_info.apptimer_total_ticks;
238         hal_pwr_config_timer_wakeup(PWR_SLP_TIMER_MODE_SINGLE,
239                                     sys_us_2_lpcycles(s_app_timer_info.apptimer_runout_time));
240     } else {
241         s_app_timer_info.apptimer_start = APP_TIMER_STOP;
242         pwr_mgmt_notify_timer_event(EVENT_APP_TIMER_STOP);
243     }
244 
245     APP_TIMER_UNLOCK();
246     if (p_exe_node && (p_exe_node->timer_node_status == APP_TIMER_NODE_START)) {
247         if (p_exe_node->next_trigger_mode == ATIMER_ONE_SHOT) {
248             p_exe_node->timer_node_status = APP_TIMER_NODE_STOP;
249         }
250 #if APP_TIMER_USE_SCHEDULER
251         app_timer_evt_t evt;
252 
253         evt.timeout_handler = p_exe_node->next_trigger_callback;
254         evt.p_ctx           = p_exe_node->next_trigger_callback_var;
255 
256         app_scheduler_evt_put(&evt, sizeof(evt), timeout_handler_scheduled_exec);
257 #else
258         p_exe_node->next_trigger_callback(p_exe_node->next_trigger_callback_var);
259 #endif
260     }
261 }
262 
263 /*
264  * GLOBAL FUNCTION DEFINITIONS
265  *****************************************************************************************
266  */
app_timer_get_status(void)267 uint8_t app_timer_get_status(void)
268 {
269     return (s_app_timer_info.apptimer_start == APP_TIMER_STOP)?0:1;
270 }
271 
app_timer_stop_and_ret(app_timer_id_t p_timer_id)272 TINY_RAM_SECTION uint32_t app_timer_stop_and_ret(app_timer_id_t p_timer_id)
273 {
274     uint32_t ret = 0;
275     uint32_t atimer_curr_ticks = 0, atimer_curr_us = 0;
276     app_timer_t *p_timer_node = p_timer_id;
277 
278     if (p_timer_node == NULL) {
279         return 0;
280     }
281 
282     hal_pwr_get_timer_current_value(PWR_TIMER_TYPE_SLP_TIMER, &atimer_curr_ticks);
283 
284     app_timer_drv_stop();
285 
286     atimer_curr_us = (uint32_t)(APP_TIMER_TICKS_TO_US(atimer_curr_ticks));
287 
288     uint32_t already_ran_time = s_app_timer_info.apptimer_runout_time - atimer_curr_us;
289 
290     s_app_timer_info.apptimer_total_ticks += already_ran_time;
291 
292     ret = s_app_timer_info.apptimer_runout_time - atimer_curr_us;
293 
294     p_timer_node->original_delay = 0x0;
295     p_timer_node->timer_node_status = APP_TIMER_NODE_STOP;
296 
297     s_app_timer_info.apptimer_start = APP_TIMER_STOP;
298     pwr_mgmt_notify_timer_event(EVENT_APP_TIMER_STOP);
299     return ret;
300 }
301 
app_timer_delete(app_timer_id_t * p_timer_id)302 sdk_err_t app_timer_delete(app_timer_id_t *p_timer_id)
303 {
304     app_timer_t *p_timer_node = *p_timer_id;
305 
306     if (p_timer_node == APP_TIMER_INVALID_ID) {
307         return SDK_ERR_INVALID_PARAM;
308     }
309 
310     APP_TIMER_LOCK();
311 
312     p_timer_node->original_delay = 0x0;
313     p_timer_node->timer_node_status = APP_TIMER_NODE_STOP;
314     p_timer_node->timer_node_used = TIMER_NODE_FREE;
315     *p_timer_id = APP_TIMER_INVALID_ID;
316 
317     if (s_app_timer_info.p_curr_timer_node == p_timer_node) {
318         app_timer_drv_stop();
319         p_timer_node = get_next_timer();
320         if (p_timer_node != NULL) {
321             s_app_timer_info.apptimer_runout_time = p_timer_node->next_trigger_time-
322                                                     s_app_timer_info.apptimer_total_ticks;
323             s_app_timer_info.p_curr_timer_node = p_timer_node;
324             hal_pwr_config_timer_wakeup(PWR_SLP_TIMER_MODE_SINGLE,
325                                         sys_us_2_lpcycles(s_app_timer_info.apptimer_runout_time));
326         } else {
327             s_app_timer_info.apptimer_start = APP_TIMER_STOP;
328             s_app_timer_info.p_curr_timer_node = NULL;
329             pwr_mgmt_notify_timer_event(EVENT_APP_TIMER_STOP);
330         }
331     }
332     APP_TIMER_UNLOCK();
333     return SDK_SUCCESS;
334 }
335 
app_timer_stop(app_timer_id_t p_timer_id)336 void app_timer_stop(app_timer_id_t p_timer_id)
337 {
338     APP_TIMER_LOCK();
339 
340     app_timer_t *p_timer_node = p_timer_id;
341     uint32_t atimer_curr_ticks = 0, atimer_curr_us = 0;
342 
343     if (p_timer_node == NULL) {
344         APP_TIMER_UNLOCK();
345         return ;
346     }
347 
348     if (p_timer_node->timer_node_status != APP_TIMER_NODE_START) {
349         APP_TIMER_UNLOCK();
350         return;
351     }
352 
353     p_timer_node->timer_node_status = APP_TIMER_NODE_STOP;
354     p_timer_node->original_delay = 0x0;
355 
356     if (s_app_timer_info.p_curr_timer_node == p_timer_node) {
357         app_timer_drv_stop();
358         APP_TIMER_GET_CURRENT_TICKS(&atimer_curr_ticks);
359 
360         atimer_curr_us = (uint32_t)(APP_TIMER_TICKS_TO_US(atimer_curr_ticks));
361 
362         if (atimer_curr_ticks == 0xFFFFFFFF) {
363             ll_pwr_clear_wakeup_event(LL_PWR_WKUP_EVENT_TIMER);
364             NVIC_ClearPendingIRQ(SLPTIMER_IRQn);
365             atimer_curr_ticks = 0;
366         }
367 
368         uint32_t already_ran_time = s_app_timer_info.apptimer_runout_time - atimer_curr_us;
369         s_app_timer_info.apptimer_total_ticks += already_ran_time;
370 
371         p_timer_node = get_next_timer();
372         if (p_timer_node != NULL) {
373             s_app_timer_info.apptimer_runout_time = p_timer_node->next_trigger_time-
374                                                     s_app_timer_info.apptimer_total_ticks;
375             s_app_timer_info.p_curr_timer_node = p_timer_node;
376             hal_pwr_config_timer_wakeup(PWR_SLP_TIMER_MODE_SINGLE,
377                                         sys_us_2_lpcycles(s_app_timer_info.apptimer_runout_time));
378         } else {
379             s_app_timer_info.apptimer_start = APP_TIMER_STOP;
380             pwr_mgmt_notify_timer_event(EVENT_APP_TIMER_STOP);
381         }
382     }
383     APP_TIMER_UNLOCK();
384     return ;
385 }
386 
app_timer_start(app_timer_id_t p_timer_id,uint32_t delay,uint8_t * p_ctx)387 TINY_RAM_SECTION sdk_err_t app_timer_start(app_timer_id_t p_timer_id, uint32_t delay, uint8_t *p_ctx)
388 {
389     app_timer_t *p_timer_node = p_timer_id;
390     uint32_t delay_time = APP_TIMER_MS_TO_US(delay);
391     uint32_t atimer_curr_ticks = 0, atimer_curr_us = 0;
392     bool is_pending_trigger = false;
393 
394     if (p_timer_node == NULL)
395         return SDK_ERR_INVALID_PARAM;
396 
397     /* DO NOT SUPPORT NULL TIMER */
398     if (delay = TIMER_INVALID_DELAY_VALUE) {
399         return SDK_ERR_INVALID_PARAM;
400     }
401 
402     APP_TIMER_LOCK();
403 
404     app_timer_t *p_cur_node = p_timer_node;
405 
406     if (p_cur_node->timer_node_status == APP_TIMER_NODE_START) {
407         APP_TIMER_UNLOCK();
408         return SDK_ERR_BUSY;
409     }
410 
411     p_cur_node->next_trigger_callback_var = p_ctx;
412     p_cur_node->timer_node_status = APP_TIMER_NODE_START;
413     /*******ther first time to start timer********/
414     if (APP_TIMER_STOP == s_app_timer_info.apptimer_start) {
415         NVIC_ClearPendingIRQ(SLPTIMER_IRQn);
416 
417         s_app_timer_info.p_curr_timer_node = p_cur_node;
418         s_app_timer_info.apptimer_runout_time = delay_time;
419         s_app_timer_info.apptimer_total_ticks = 0x0;
420         s_app_timer_info.apptimer_start = APP_TIMER_START;
421 
422         p_cur_node->original_delay = delay_time;
423         p_cur_node->next_trigger_time = delay_time + s_app_timer_info.apptimer_total_ticks;
424 
425         hal_pwr_config_timer_wakeup(PWR_SLP_TIMER_MODE_SINGLE,
426                                     sys_us_2_lpcycles(s_app_timer_info.apptimer_runout_time));
427         /*
428          * < NVIC_EnableIRQ(SLPTIMER_IRQn) >
429          * This function must be placed after initializing the parameters of timer,
430          * otherwise an unprepared timer interrupt may be triggered ahead of time, leading to hardfault.
431         */
432         NVIC_EnableIRQ(SLPTIMER_IRQn);
433     } else {
434         /*
435             To stop sleep timer counter. if time expired at this time,
436             the counter of sleep timer will filled with 0xFFFFFFFF.
437         */
438         if (s_app_timer_info.p_curr_timer_node->original_delay >= delay_time) {
439             app_timer_drv_stop();
440         }
441 
442         /* To get current counter in sleep timer. */
443         APP_TIMER_GET_CURRENT_TICKS(&atimer_curr_ticks);
444 
445         /* Current counter transform to u-second. */
446         atimer_curr_us = (uint32_t)(APP_TIMER_TICKS_TO_US(atimer_curr_ticks));
447 
448         /*
449            Because when the sleep timer counts to zero,
450            the counter value will automatically be 0xFFFFFFFF.
451            so we need to manually change to 0 and set is_pending_trigger to true.
452         */
453         if (atimer_curr_ticks == 0xFFFFFFFF) {
454             atimer_curr_us = 0x0;
455             is_pending_trigger = true;
456         }
457 
458         /* To get the rest of ran time of the current timer node. */
459         uint32_t already_ran_time = s_app_timer_info.apptimer_runout_time - atimer_curr_us;
460 
461         if (atimer_curr_us > delay_time) {
462             s_app_timer_info.p_curr_timer_node = p_cur_node;
463             s_app_timer_info.apptimer_runout_time = delay_time;
464         }
465 
466         p_cur_node->original_delay = delay_time;
467 
468         if (s_app_timer_info.p_curr_timer_node->original_delay >= delay_time) {
469             if (is_pending_trigger == false) {
470                 s_app_timer_info.apptimer_total_ticks += already_ran_time;
471                 p_cur_node->next_trigger_time = delay_time + s_app_timer_info.apptimer_total_ticks;
472             } else {
473                 p_cur_node->next_trigger_time = delay_time + s_app_timer_info.apptimer_total_ticks + already_ran_time;
474             }
475 
476             if (is_pending_trigger == false) {
477                 s_app_timer_info.apptimer_runout_time = s_app_timer_info.p_curr_timer_node->next_trigger_time -
478                                                         s_app_timer_info.apptimer_total_ticks;
479                 if (s_app_timer_info.apptimer_runout_time < 0) {
480                     s_app_timer_info.apptimer_runout_time = 0;
481                 }
482                 hal_pwr_config_timer_wakeup(PWR_SLP_TIMER_MODE_SINGLE,
483                                             sys_us_2_lpcycles(s_app_timer_info.apptimer_runout_time));
484             }
485         } else {
486             p_cur_node->next_trigger_time = delay_time + s_app_timer_info.apptimer_total_ticks + already_ran_time;
487         }
488     }
489 
490     pwr_mgmt_notify_timer_event(EVENT_APP_TIMER_START);
491 
492     APP_TIMER_UNLOCK();
493     return SDK_SUCCESS;
494 }
495 
app_timer_create(app_timer_id_t * p_timer_id,app_timer_type_t mode,app_timer_fun_t callback)496 sdk_err_t app_timer_create(app_timer_id_t *p_timer_id, app_timer_type_t mode, app_timer_fun_t callback)
497 {
498     uint8_t handle = TIMER_INVALID_NODE_NUMBER;
499 
500     if (callback == NULL)
501         return SDK_ERR_INVALID_PARAM;
502 
503     /* p_timer_id is already in use */
504     if (*p_timer_id != NULL)
505         return SDK_ERR_DISALLOWED;
506 
507     APP_TIMER_LOCK();
508 
509     /* pick up one null item for new timer node */
510     handle = app_timer_get_valid_node();
511     if (handle == TIMER_INVALID_NODE_NUMBER) {
512         *p_timer_id = NULL;
513         APP_TIMER_UNLOCK();
514         return SDK_ERR_LIST_FULL;
515     }
516     app_timer_set_var(handle, mode, callback);
517 
518     *p_timer_id = &s_timer_node[handle];
519     APP_TIMER_UNLOCK();
520     return SDK_SUCCESS;
521 }
522