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