• 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     uint32_t __l_irq_rest = __get_BASEPRI();   \
69     __set_BASEPRI(NVIC_GetPriority(BLE_IRQn) + \
70                   (1 << (NVIC_GetPriorityGrouping() + 1)))
71 
72 #define LOCAL_APP_TIMER_UNLOCK() \
73     __set_BASEPRI(__l_irq_rest)
74 
75 /**@brief The length of timer node list. */
76 #define TIMER_NODE_CNT                 20
77 #define TIMER_INVALID_DELAY_VALUE      0
78 #define TIMER_INVALID_NODE_NUMBER      0xFF
79 #define APP_TIMER_STOP_VALUE           0x1
80 #define APP_TIMER_INVALID_ID           NULL
81 #define APP_TIMER_SUC                  0x0
82 #define APP_TIMER_FAIL                 (-1)
83 #define APP_TIMER_LOCK()               LOCAL_APP_TIMER_LOCK()
84 #define APP_TIMER_UNLOCK()             LOCAL_APP_TIMER_UNLOCK()
85 
APP_TIMER_MS_TO_US(uint32_t x)86 static inline uint32_t APP_TIMER_MS_TO_US(uint32_t x)
87 {
88     return x * 1000UL;
89 }
90 
APP_TIMER_TICKS_TO_US(uint32_t x)91 static inline float APP_TIMER_TICKS_TO_US(uint32_t x)
92 {
93     float ret = ((x) * 1000000.0f / sys_lpclk_get());
94     return ret;
95 }
96 
APP_TIMER_GET_CURRENT_TICKS(uint32_t x)97 static inline void APP_TIMER_GET_CURRENT_TICKS(uint32_t x)
98 {
99     hal_pwr_get_timer_current_value(PWR_TIMER_TYPE_SLP_TIMER, x);
100 }
101 
102 /**@brief App timer global state variable. */
103 typedef struct app_timer_struct {
104     uint8_t                   apptimer_start;
105     uint8_t                   apptimer_in_int;
106     app_timer_t               *p_curr_timer_node;
107     int                       apptimer_runout_time;
108     uint32_t                  apptimer_total_ticks;
109     uint32_t                  apptimer_total_ticks_us;
110 } app_timer_info_t;
111 
112 
113 /**@brief App timer state types. */
114 enum {
115     APP_TIMER_STOP = 0,
116     APP_TIMER_START,
117 };
118 
119 /**@brief App timer state types. */
120 enum {
121     TIMER_NODE_FREE = 0,
122     TIMER_NODE_USED,
123 };
124 
125 /**@brief App timer state types. */
126 enum {
127     APP_TIMER_NODE_START = 0xaa,
128     APP_TIMER_NODE_STOP,
129 };
130 
131 /**@brief Aon-timer global list, all newly added timer nodes will be added to the queue. */
132 static app_timer_t      s_timer_node[TIMER_NODE_CNT];
133 static app_timer_info_t s_app_timer_info;
134 
135 /*
136  * LOCAL VARIABLE DEFINITIONS
137  *****************************************************************************************
138  */
get_next_timer(void)139 app_timer_t* get_next_timer(void)
140 {
141     int min_handle = TIMER_INVALID_NODE_NUMBER;
142     uint32_t min_value = (uint32_t)0xFFFFFFFF;
143 
144     for (int idx = 0; idx < TIMER_NODE_CNT; idx++) {
145         if (s_timer_node[idx].original_delay && (s_timer_node[idx].timer_node_status == APP_TIMER_NODE_START)) {
146             if ((s_timer_node[idx].next_trigger_time - s_app_timer_info.apptimer_total_ticks) < min_value) {
147                 min_value = s_timer_node[idx].next_trigger_time - s_app_timer_info.apptimer_total_ticks;
148                 min_handle = idx;
149             } else if (s_timer_node[idx].next_trigger_time < s_app_timer_info.apptimer_total_ticks) {
150                 s_timer_node[idx].next_trigger_time = s_app_timer_info.apptimer_total_ticks;
151                 min_value = 0;
152                 min_handle = idx;
153             }
154 
155             if (min_value == 0) {
156                 return &s_timer_node[min_handle];
157             }
158         }
159     }
160 
161     if (min_handle == TIMER_INVALID_NODE_NUMBER) {
162         return NULL;
163     }
164 
165     return &s_timer_node[min_handle];
166 }
167 
clear_total_ticks(void)168 void clear_total_ticks(void)
169 {
170     if (s_app_timer_info.apptimer_total_ticks >= 0xF0000000) {
171         for (int idx = 0; idx < TIMER_NODE_CNT; idx++) {
172             if (s_timer_node[idx].original_delay) {
173                 s_timer_node[idx].next_trigger_time -= s_app_timer_info.apptimer_total_ticks;
174             }
175         }
176         s_app_timer_info.apptimer_total_ticks = 0x0;
177     }
178 }
179 
app_timer_drv_stop(void)180 __STATIC_INLINE void app_timer_drv_stop(void)
181 {
182     hal_pwr_config_timer_wakeup(PWR_SLP_TIMER_MODE_DISABLE, APP_TIMER_STOP_VALUE);
183 }
184 
app_timer_get_valid_node(void)185 uint8_t app_timer_get_valid_node(void)
186 {
187     uint8_t idx = 0;
188     for (idx=0; idx<TIMER_NODE_CNT; idx ++) {
189         if (TIMER_NODE_FREE == s_timer_node[idx].timer_node_used) {
190             s_timer_node[idx].timer_node_used = TIMER_NODE_USED;
191             return idx;
192         }
193     }
194     return TIMER_INVALID_NODE_NUMBER;
195 }
196 
app_timer_set_var(uint8_t handle,uint8_t atimer_mode,app_timer_fun_t callback)197 void app_timer_set_var(uint8_t handle, uint8_t atimer_mode, app_timer_fun_t callback)
198 {
199     s_timer_node[handle].next_trigger_callback = callback;
200     s_timer_node[handle].next_trigger_mode = atimer_mode;
201 }
202 
203 
204 #if APP_TIMER_USE_SCHEDULER
timeout_handler_scheduled_exec(void * p_evt_data,uint16_t evt_size)205 static void timeout_handler_scheduled_exec(void * p_evt_data, uint16_t evt_size)
206 {
207     app_timer_evt_t const *p_timer_evt = (app_timer_evt_t *)p_evt_data;
208 
209     p_timer_evt->timeout_handler(p_timer_evt->p_ctx);
210 }
211 #endif
212 
hal_pwr_sleep_timer_elapsed_callback(void)213 TINY_RAM_SECTION void hal_pwr_sleep_timer_elapsed_callback(void)
214 {
215     APP_TIMER_LOCK();
216 
217     app_timer_t *p_timer_node = s_app_timer_info.p_curr_timer_node;
218     app_timer_t *p_exe_node = p_timer_node;
219     s_app_timer_info.apptimer_total_ticks += s_app_timer_info.apptimer_runout_time;
220 
221     if (p_timer_node->next_trigger_mode == ATIMER_ONE_SHOT) {
222         p_timer_node->original_delay = 0x0;
223     } else if (p_timer_node->next_trigger_mode == ATIMER_REPEAT) {
224         p_timer_node->next_trigger_time = p_timer_node->original_delay + s_app_timer_info.apptimer_total_ticks;
225     }
226 
227     clear_total_ticks();
228     s_app_timer_info.p_curr_timer_node = get_next_timer();
229     p_timer_node = s_app_timer_info.p_curr_timer_node;
230 
231     if (s_app_timer_info.p_curr_timer_node != NULL) {
232         s_app_timer_info.apptimer_runout_time = p_timer_node->next_trigger_time-s_app_timer_info.apptimer_total_ticks;
233         hal_pwr_config_timer_wakeup(PWR_SLP_TIMER_MODE_SINGLE,
234                                     sys_us_2_lpcycles(s_app_timer_info.apptimer_runout_time));
235     } else {
236         s_app_timer_info.apptimer_start = APP_TIMER_STOP;
237         pwr_mgmt_notify_timer_event(EVENT_APP_TIMER_STOP);
238     }
239 
240     APP_TIMER_UNLOCK();
241     if (p_exe_node && (p_exe_node->timer_node_status == APP_TIMER_NODE_START)) {
242         if (p_exe_node->next_trigger_mode == ATIMER_ONE_SHOT) {
243             p_exe_node->timer_node_status = APP_TIMER_NODE_STOP;
244         }
245 #if APP_TIMER_USE_SCHEDULER
246         app_timer_evt_t evt;
247 
248         evt.timeout_handler = p_exe_node->next_trigger_callback;
249         evt.p_ctx           = p_exe_node->next_trigger_callback_var;
250 
251         app_scheduler_evt_put(&evt, sizeof(evt), timeout_handler_scheduled_exec);
252 #else
253         p_exe_node->next_trigger_callback(p_exe_node->next_trigger_callback_var);
254 #endif
255     }
256 }
257 
258 /*
259  * GLOBAL FUNCTION DEFINITIONS
260  *****************************************************************************************
261  */
app_timer_get_status(void)262 uint8_t app_timer_get_status(void)
263 {
264     return (s_app_timer_info.apptimer_start == APP_TIMER_STOP)?0:1;
265 }
266 
app_timer_stop_and_ret(app_timer_id_t p_timer_id)267 TINY_RAM_SECTION uint32_t app_timer_stop_and_ret(app_timer_id_t p_timer_id)
268 {
269     uint32_t ret = 0;
270     uint32_t atimer_curr_ticks = 0, atimer_curr_us = 0;
271     app_timer_t *p_timer_node = p_timer_id;
272 
273     if (p_timer_node == NULL) {
274         return 0;
275     }
276 
277     hal_pwr_get_timer_current_value(PWR_TIMER_TYPE_SLP_TIMER, &atimer_curr_ticks);
278 
279     app_timer_drv_stop();
280 
281     atimer_curr_us = (uint32_t)(APP_TIMER_TICKS_TO_US(atimer_curr_ticks));
282 
283     uint32_t already_ran_time = s_app_timer_info.apptimer_runout_time - atimer_curr_us;
284 
285     s_app_timer_info.apptimer_total_ticks += already_ran_time;
286 
287     ret = s_app_timer_info.apptimer_runout_time - atimer_curr_us;
288 
289     p_timer_node->original_delay = 0x0;
290     p_timer_node->timer_node_status = APP_TIMER_NODE_STOP;
291 
292     s_app_timer_info.apptimer_start = APP_TIMER_STOP;
293     pwr_mgmt_notify_timer_event(EVENT_APP_TIMER_STOP);
294     return ret;
295 }
296 
app_timer_delete(app_timer_id_t * p_timer_id)297 sdk_err_t app_timer_delete(app_timer_id_t *p_timer_id)
298 {
299     app_timer_t *p_timer_node = *p_timer_id;
300 
301     if (p_timer_node == APP_TIMER_INVALID_ID) {
302         return SDK_ERR_INVALID_PARAM;
303     }
304 
305     APP_TIMER_LOCK();
306 
307     p_timer_node->original_delay = 0x0;
308     p_timer_node->timer_node_status = APP_TIMER_NODE_STOP;
309     p_timer_node->timer_node_used = TIMER_NODE_FREE;
310     *p_timer_id = APP_TIMER_INVALID_ID;
311 
312     if (s_app_timer_info.p_curr_timer_node == p_timer_node) {
313         app_timer_drv_stop();
314         p_timer_node = get_next_timer();
315         if (p_timer_node != NULL) {
316             s_app_timer_info.apptimer_runout_time = p_timer_node->next_trigger_time-
317                                                     s_app_timer_info.apptimer_total_ticks;
318             s_app_timer_info.p_curr_timer_node = p_timer_node;
319             hal_pwr_config_timer_wakeup(PWR_SLP_TIMER_MODE_SINGLE,
320                                         sys_us_2_lpcycles(s_app_timer_info.apptimer_runout_time));
321         } else {
322             s_app_timer_info.apptimer_start = APP_TIMER_STOP;
323             s_app_timer_info.p_curr_timer_node = NULL;
324             pwr_mgmt_notify_timer_event(EVENT_APP_TIMER_STOP);
325         }
326     }
327     APP_TIMER_UNLOCK();
328     return SDK_SUCCESS;
329 }
330 
app_timer_stop(app_timer_id_t p_timer_id)331 void app_timer_stop(app_timer_id_t p_timer_id)
332 {
333     APP_TIMER_LOCK();
334 
335     app_timer_t *p_timer_node = p_timer_id;
336     uint32_t atimer_curr_ticks = 0, atimer_curr_us = 0;
337 
338     if (p_timer_node == NULL) {
339         APP_TIMER_UNLOCK();
340         return ;
341     }
342 
343     if (p_timer_node->timer_node_status != APP_TIMER_NODE_START) {
344         APP_TIMER_UNLOCK();
345         return;
346     }
347 
348     p_timer_node->timer_node_status = APP_TIMER_NODE_STOP;
349     p_timer_node->original_delay = 0x0;
350 
351     if (s_app_timer_info.p_curr_timer_node == p_timer_node) {
352         app_timer_drv_stop();
353         APP_TIMER_GET_CURRENT_TICKS(&atimer_curr_ticks);
354 
355         atimer_curr_us = (uint32_t)(APP_TIMER_TICKS_TO_US(atimer_curr_ticks));
356 
357         if (atimer_curr_ticks == 0xFFFFFFFF) {
358             ll_pwr_clear_wakeup_event(LL_PWR_WKUP_EVENT_TIMER);
359             NVIC_ClearPendingIRQ(SLPTIMER_IRQn);
360             atimer_curr_ticks = 0;
361         }
362 
363         uint32_t already_ran_time = s_app_timer_info.apptimer_runout_time - atimer_curr_us;
364         s_app_timer_info.apptimer_total_ticks += already_ran_time;
365 
366         p_timer_node = get_next_timer();
367         if (p_timer_node != NULL) {
368             s_app_timer_info.apptimer_runout_time = p_timer_node->next_trigger_time-
369                                                     s_app_timer_info.apptimer_total_ticks;
370             s_app_timer_info.p_curr_timer_node = p_timer_node;
371             hal_pwr_config_timer_wakeup(PWR_SLP_TIMER_MODE_SINGLE,
372                                         sys_us_2_lpcycles(s_app_timer_info.apptimer_runout_time));
373         } else {
374             s_app_timer_info.apptimer_start = APP_TIMER_STOP;
375             pwr_mgmt_notify_timer_event(EVENT_APP_TIMER_STOP);
376         }
377     }
378     APP_TIMER_UNLOCK();
379     return ;
380 }
381 
app_timer_start(app_timer_id_t p_timer_id,uint32_t delay,uint8_t * p_ctx)382 TINY_RAM_SECTION sdk_err_t app_timer_start(app_timer_id_t p_timer_id, uint32_t delay, uint8_t *p_ctx)
383 {
384     app_timer_t *p_timer_node = p_timer_id;
385     uint32_t delay_time = APP_TIMER_MS_TO_US(delay);
386     uint32_t atimer_curr_ticks = 0, atimer_curr_us = 0;
387     bool is_pending_trigger = false;
388 
389     if (p_timer_node == NULL)
390         return SDK_ERR_INVALID_PARAM;
391 
392     /* DO NOT SUPPORT NULL TIMER */
393     if (delay = TIMER_INVALID_DELAY_VALUE) {
394         return SDK_ERR_INVALID_PARAM;
395     }
396 
397     APP_TIMER_LOCK();
398 
399     app_timer_t *p_cur_node = p_timer_node;
400 
401     if (p_cur_node->timer_node_status == APP_TIMER_NODE_START) {
402         APP_TIMER_UNLOCK();
403         return SDK_ERR_BUSY;
404     }
405 
406     p_cur_node->next_trigger_callback_var = p_ctx;
407     p_cur_node->timer_node_status = APP_TIMER_NODE_START;
408     /*******ther first time to start timer********/
409     if (APP_TIMER_STOP == s_app_timer_info.apptimer_start) {
410         NVIC_ClearPendingIRQ(SLPTIMER_IRQn);
411 
412         s_app_timer_info.p_curr_timer_node = p_cur_node;
413         s_app_timer_info.apptimer_runout_time = delay_time;
414         s_app_timer_info.apptimer_total_ticks = 0x0;
415         s_app_timer_info.apptimer_start = APP_TIMER_START;
416 
417         p_cur_node->original_delay = delay_time;
418         p_cur_node->next_trigger_time = delay_time + s_app_timer_info.apptimer_total_ticks;
419 
420         hal_pwr_config_timer_wakeup(PWR_SLP_TIMER_MODE_SINGLE,
421                                     sys_us_2_lpcycles(s_app_timer_info.apptimer_runout_time));
422         /*
423          * < NVIC_EnableIRQ(SLPTIMER_IRQn) >
424          * This function must be placed after initializing the parameters of timer,
425          * otherwise an unprepared timer interrupt may be triggered ahead of time, leading to hardfault.
426         */
427         NVIC_EnableIRQ(SLPTIMER_IRQn);
428     } else {
429         /*
430             To stop sleep timer counter. if time expired at this time,
431             the counter of sleep timer will filled with 0xFFFFFFFF.
432         */
433         if (s_app_timer_info.p_curr_timer_node->original_delay >= delay_time) {
434             app_timer_drv_stop();
435         }
436 
437         /* To get current counter in sleep timer. */
438         APP_TIMER_GET_CURRENT_TICKS(&atimer_curr_ticks);
439 
440         /* Current counter transform to u-second. */
441         atimer_curr_us = (uint32_t)(APP_TIMER_TICKS_TO_US(atimer_curr_ticks));
442 
443         /*
444            Because when the sleep timer counts to zero,
445            the counter value will automatically be 0xFFFFFFFF.
446            so we need to manually change to 0 and set is_pending_trigger to true.
447         */
448         if (atimer_curr_ticks == 0xFFFFFFFF) {
449             atimer_curr_us = 0x0;
450             is_pending_trigger = true;
451         }
452 
453         /* To get the rest of ran time of the current timer node. */
454         uint32_t already_ran_time = s_app_timer_info.apptimer_runout_time - atimer_curr_us;
455 
456         if (atimer_curr_us > delay_time) {
457             s_app_timer_info.p_curr_timer_node = p_cur_node;
458             s_app_timer_info.apptimer_runout_time = delay_time;
459         }
460 
461         p_cur_node->original_delay = delay_time;
462 
463         if (s_app_timer_info.p_curr_timer_node->original_delay >= delay_time) {
464             if (is_pending_trigger == false) {
465                 s_app_timer_info.apptimer_total_ticks += already_ran_time;
466                 p_cur_node->next_trigger_time = delay_time + s_app_timer_info.apptimer_total_ticks;
467                 s_app_timer_info.apptimer_runout_time = s_app_timer_info.p_curr_timer_node->next_trigger_time -
468                                                         s_app_timer_info.apptimer_total_ticks;
469             } else {
470                 p_cur_node->next_trigger_time = delay_time + s_app_timer_info.apptimer_total_ticks + already_ran_time;
471             }
472 
473             if ((is_pending_trigger == false)&&(s_app_timer_info.apptimer_runout_time < 0)) {
474                     s_app_timer_info.apptimer_runout_time = 0;
475             }
476             if (is_pending_trigger == false) {
477                 hal_pwr_config_timer_wakeup(PWR_SLP_TIMER_MODE_SINGLE,
478                                             sys_us_2_lpcycles(s_app_timer_info.apptimer_runout_time));
479             }
480         } else {
481             p_cur_node->next_trigger_time = delay_time + s_app_timer_info.apptimer_total_ticks + already_ran_time;
482         }
483     }
484 
485     pwr_mgmt_notify_timer_event(EVENT_APP_TIMER_START);
486 
487     APP_TIMER_UNLOCK();
488     return SDK_SUCCESS;
489 }
490 
app_timer_create(app_timer_id_t * p_timer_id,app_timer_type_t mode,app_timer_fun_t callback)491 sdk_err_t app_timer_create(app_timer_id_t *p_timer_id, app_timer_type_t mode, app_timer_fun_t callback)
492 {
493     uint8_t handle = TIMER_INVALID_NODE_NUMBER;
494 
495     if (callback == NULL)
496         return SDK_ERR_INVALID_PARAM;
497 
498     /* p_timer_id is already in use */
499     if (*p_timer_id != NULL)
500         return SDK_ERR_DISALLOWED;
501 
502     APP_TIMER_LOCK();
503 
504     /* pick up one null item for new timer node */
505     handle = app_timer_get_valid_node();
506     if (handle == TIMER_INVALID_NODE_NUMBER) {
507         *p_timer_id = NULL;
508         APP_TIMER_UNLOCK();
509         return SDK_ERR_LIST_FULL;
510     }
511     app_timer_set_var(handle, mode, callback);
512 
513     *p_timer_id = &s_timer_node[handle];
514     APP_TIMER_UNLOCK();
515     return SDK_SUCCESS;
516 }
517