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