/**
|
*******************************************************************************
|
* @file app_timer.c
|
* @create 2023-08-01
|
* @author Panchip BLE GROUP
|
* @note
|
* Copyright (c) Shanghai Panchip Microelectronics Co.,Ltd.
|
*
|
*******************************************************************************
|
*/
|
#include "app_timer.h"
|
#include "PanSeries.h"
|
#include "utils/fifo.h"
|
#include "utils/critical.h"
|
#include "sort_queue.h"
|
#include "soc_api.h"
|
|
#if defined(IP_107x) || defined(IP_101x)
|
static app_timer_t *cur_active_timer = NULL;
|
static bool global_active = false;
|
|
/**
|
* @brief Timer requests types.
|
*/
|
typedef enum{
|
TIMER_REQ_START,
|
TIMER_REQ_STOP,
|
TIMER_REQ_STOP_ALL
|
}timer_req_type_t;
|
|
/**
|
* @brief Operation request structure.
|
*/
|
typedef struct{
|
app_timer_t *p_timer; /**< Timer instance. */
|
timer_req_type_t type; /**< Request type. */
|
}timer_req_t;
|
|
FIFO_DEFINE(timer_req_fifo, MEM_ALIGNED4(sizeof(timer_req_t)), APP_TIMER_REQ_FIFO_ITEM_NUM);
|
|
bool sort_list_compare_func(sort_queue_item_t *item0, sort_queue_item_t *item1);
|
SORT_QUEUE_INIT(app_timer_sort_queue, sort_list_compare_func);
|
|
|
static bool time_little(uint32_t t1, uint32_t t2)
|
{
|
return (uint32_t)(t1 - t2) > BIT(30) ? true:false;
|
}
|
|
bool sort_list_compare_func(sort_queue_item_t *item0, sort_queue_item_t *item1)
|
{
|
app_timer_t *ptimer0 = (app_timer_t *)item0;
|
app_timer_t *ptimer1 = (app_timer_t *)item1;
|
|
if(time_little(ptimer0->endVal, ptimer1->endVal)){
|
return true;
|
}
|
return false;
|
}
|
|
uint32_t sort_list_cnt(void)
|
{
|
return sort_queue_cnt(&app_timer_sort_queue);
|
}
|
|
void sort_list_add(app_timer_t *ptimer)
|
{
|
sort_queue_add(&app_timer_sort_queue, (sort_queue_item_t *)ptimer);
|
}
|
|
app_timer_t *sort_list_pop(void)
|
{
|
return (app_timer_t *)sort_queue_pop(&app_timer_sort_queue);
|
}
|
|
app_timer_t *sort_list_peek(void)
|
{
|
return (app_timer_t *)sort_queue_peek(&app_timer_sort_queue);
|
}
|
|
void sort_list_remove(app_timer_t *ptimer)
|
{
|
sort_queue_remove(&app_timer_sort_queue, (sort_queue_item_t *)ptimer);
|
}
|
|
void sort_list_remove_all(void)
|
{
|
app_timer_t *p_cur_timer = NULL;
|
do {
|
p_cur_timer = sort_list_pop();
|
if(p_cur_timer){
|
p_cur_timer->endVal = APP_TIMER_IDLE_VAL;
|
}
|
}while(p_cur_timer);
|
}
|
|
static void timer_req_trigger(void)
|
{
|
NVIC_SetPendingIRQ(SLPTMR_IRQn);
|
}
|
|
static int timer_req_send(app_timer_t *ptimer, timer_req_type_t type)
|
{
|
fifo_t *pfifo = &timer_req_fifo;
|
if(FIFO_IsFull(pfifo)){
|
return APP_TIMER_NO_MEM;
|
}
|
|
timer_req_t *ptimer_req = (timer_req_t *)FIFO_GetWriteBuf(pfifo);
|
|
ptimer_req->type = type;
|
ptimer_req->p_timer = ptimer;
|
|
FIFO_MoveToNextWriteBuf(pfifo);
|
|
timer_req_trigger();
|
|
return APP_TIMER_OK;
|
}
|
|
static void timer_req_handler(void)
|
{
|
fifo_t *pfifo = &timer_req_fifo;
|
|
while(pfifo->w != pfifo->r)
|
{
|
timer_req_t *ptimer_req = (timer_req_t *)FIFO_GetReadBuf(pfifo);
|
app_timer_t *ptimer = ptimer_req->p_timer;
|
|
switch(ptimer_req->type)
|
{
|
case TIMER_REQ_START:
|
if(!APP_TIMER_IS_IDLE(ptimer)){
|
sort_list_add(ptimer);
|
}
|
break;
|
|
case TIMER_REQ_STOP:
|
if(ptimer == cur_active_timer){
|
cur_active_timer = NULL;
|
}
|
else{
|
sort_list_remove(ptimer);
|
}
|
break;
|
|
case TIMER_REQ_STOP_ALL:
|
sort_list_remove_all();
|
global_active = true;
|
break;
|
|
default:
|
break;
|
}
|
|
FIFO_MoveToNextReadBuf(pfifo); // must
|
}
|
}
|
|
uint32_t app_timer_get_cnt_tick(void)
|
{
|
#if 1
|
soc_busy_wait(35);//must wait 1 32k cycle when read 32k cnt
|
return ANA->LP_SLPTMR;
|
#else
|
return soc_lptmr_cycle_get(); //!!!Note: BLE MAC clock must be enabled.
|
#endif
|
}
|
|
void app_timer_set_cmp(uint32_t tick)
|
{
|
ANA->LP_SPACING_TIME1 = tick;
|
}
|
|
static void app_timer_expired(app_timer_t *ptimer)
|
{
|
if(global_active == false)
|
return;
|
|
uint32_t cpu_state = 0;
|
|
if(ptimer)
|
{
|
ENTER_CRITICAL(cpu_state);
|
if(ptimer->reloadPeriod == 0){
|
ptimer->endVal = APP_TIMER_IDLE_VAL;
|
}
|
EXIT_CRITICAL(cpu_state);
|
|
if(ptimer->handler){
|
ptimer->handler(ptimer->ctxt);
|
}
|
|
ENTER_CRITICAL(cpu_state);
|
/* check active flag as it may have been stopped in the user handler */
|
if(ptimer->reloadPeriod && !APP_TIMER_IS_IDLE(ptimer)){
|
ptimer->endVal += ptimer->reloadPeriod;
|
|
//push timer to queue
|
sort_list_add(ptimer);
|
}
|
EXIT_CRITICAL(cpu_state);
|
}
|
}
|
|
static void app_timer_update(void)
|
{
|
app_timer_t *ptimer = NULL;
|
bool reconfig = false;
|
while(1)
|
{
|
ptimer = sort_list_peek();
|
if(ptimer == NULL){
|
break;
|
}
|
|
if(APP_TIMER_IS_IDLE(ptimer)){
|
sort_list_pop();
|
continue;
|
}
|
else if(cur_active_timer == NULL){
|
reconfig = true;
|
}
|
else if(time_little(ptimer->endVal, cur_active_timer->endVal)){
|
if(!APP_TIMER_IS_IDLE(cur_active_timer)){
|
sort_list_add(cur_active_timer);
|
}
|
reconfig = true;
|
}
|
|
if(!reconfig){
|
break;
|
}
|
|
ptimer = sort_list_pop();
|
if((uint32_t)((app_timer_get_cnt_tick()+APP_TIMER_MIN_TIMEOUT_TICKS) - ptimer->endVal) > BIT(30)){
|
cur_active_timer = ptimer;
|
app_timer_set_cmp((uint32_t)(ptimer->endVal - app_timer_get_cnt_tick()));
|
break; //select ok
|
}
|
else{
|
//timer expired
|
app_timer_expired(ptimer);
|
cur_active_timer = NULL;
|
|
// select next timer object
|
}
|
}
|
}
|
|
void sleep_timer1_handler(void)
|
{
|
if(cur_active_timer){
|
app_timer_expired(cur_active_timer);
|
cur_active_timer = NULL;
|
}
|
}
|
|
void sleep_timer_post_irq_handler(void)
|
{
|
timer_req_handler();
|
app_timer_update();
|
}
|
|
void sleep_timer_it_config(uint8_t en)
|
{
|
#define LP_INT_REG_WR_BIT_MASK (BIT(0) | BIT(16) | BIT(20))
|
|
uint32_t state = ANA->LP_INT_CTRL;
|
|
if(en){
|
ANA->LP_INT_CTRL = (state & LP_INT_REG_WR_BIT_MASK) | ANAC_INT_SLEEP_TMR_INT_EN_Msk;
|
}
|
else{
|
ANA->LP_INT_CTRL = (state & LP_INT_REG_WR_BIT_MASK) & (~ANAC_INT_SLEEP_TMR_INT_EN_Msk);
|
}
|
}
|
|
int app_timer_init(void)
|
{
|
sleep_timer_it_config(ENABLE);
|
NVIC_ClearPendingIRQ(SLPTMR_IRQn);
|
NVIC_EnableIRQ(SLPTMR_IRQn);
|
|
global_active = true;
|
|
return APP_TIMER_OK;
|
}
|
|
int app_timer_create(app_timer_t *ptimer, app_timer_mode_t mode, app_timer_timeout_handler_t timeout_handler)
|
{
|
ptimer->endVal = APP_TIMER_IDLE_VAL;
|
ptimer->handler = timeout_handler;
|
ptimer->reloadPeriod = (mode == APP_TIMER_MODE_REPEATED ? 1:0);
|
|
return APP_TIMER_OK;
|
}
|
|
int app_timer_start(app_timer_t *ptimer, uint32_t timeout_ticks, void *ctxt)
|
{
|
uint32_t cpu_state = 0;
|
|
if(APP_TIMER_IS_IDLE(ptimer))
|
{
|
ENTER_CRITICAL(cpu_state);
|
ptimer->endVal = app_timer_get_cnt_tick() + timeout_ticks;
|
EXIT_CRITICAL(cpu_state);
|
|
ptimer->ctxt = ctxt;
|
|
if(ptimer->reloadPeriod){
|
ptimer->reloadPeriod = timeout_ticks;
|
}
|
|
return timer_req_send(ptimer, TIMER_REQ_START);
|
}
|
return APP_TIMER_OK;
|
}
|
|
int app_timer_stop(app_timer_t *ptimer)
|
{
|
if(APP_TIMER_IS_IDLE(ptimer)){
|
return APP_TIMER_OK;
|
}
|
|
uint32_t cpu_state = 0;
|
ENTER_CRITICAL(cpu_state);
|
ptimer->endVal = APP_TIMER_IDLE_VAL;
|
EXIT_CRITICAL(cpu_state);
|
|
return timer_req_send(ptimer, TIMER_REQ_STOP);
|
}
|
|
int app_timer_stop_all(void)
|
{
|
global_active = false;
|
return timer_req_send(NULL, TIMER_REQ_STOP_ALL);
|
}
|
|
|
|
|
#if APP_TIMER_TEST_EN
|
#include "pan_ble.h"
|
app_timer_t app_timer1;
|
app_timer_t app_timer2;
|
|
|
void app_timer1_cb(void *ctxt)
|
{
|
static uint8_t flag = 1;
|
|
DBG_CHN6_TOGGLE
|
|
if(flag){
|
app_timer_stop(&app_timer2);
|
flag = 0;
|
}
|
else{
|
flag = 1;
|
app_timer_start(&app_timer2, (100*32), NULL);
|
}
|
}
|
|
void app_timer2_cb(void *ctxt)
|
{
|
DBG_CHN5_TOGGLE
|
}
|
|
void app_timer_test(void)
|
{
|
app_timer_init();
|
|
app_timer_create(&app_timer1, APP_TIMER_MODE_REPEATED, app_timer1_cb);
|
app_timer_create(&app_timer2, APP_TIMER_MODE_REPEATED, app_timer2_cb);
|
|
app_timer_start(&app_timer1, (500*32), NULL);
|
app_timer_start(&app_timer2, (100*32), NULL);
|
}
|
#endif
|
|
#endif
|