| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 |
- /*
- * Copyright (c) 2022 OpenLuat & AirM2M
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- #include "user.h"
- //#define TM_DBG DBG_INFO
- #define TM_DBG(X, Y...)
- extern const uint32_t __os_heap_start;
- struct Timer_InfoStruct
- {
- llist_head Node;
- uint64_t TargetTick;
- uint64_t AddTick;
- uint32_t ID;
- CBFuncEx_t CallBack;
- void *Param;
- void *Handle;
- };
- #define Timer_t struct Timer_InfoStruct
- typedef struct
- {
- llist_head Head;
- uint64_t NextTick;
- uint32_t IDSn;
- uint8_t SleepFlush;
- }Timer_CtrlStruct;
- static Timer_t prvTimer[TIMER_SN_MAX];
- static Timer_CtrlStruct prvTimerCtrl;
- static void Timer_Update(Timer_t *Timer, uint64_t AddTick, uint8_t IsNew)
- {
- if (IsNew)
- {
- Timer->TargetTick = GetSysTick();
- }
- Timer->TargetTick = Timer->TargetTick + AddTick;
- }
- static void Timer_SetNextIsr(void)
- {
- uint32_t Critical = OS_EnterCritical();
- volatile uint32_t clr;
- Timer_t *Timer = (Timer_t *)prvTimerCtrl.Head.next;
- uint64_t NowTick, PassTick;
- if (llist_empty(&prvTimerCtrl.Head))
- {
- TIMM0->TIM[SYS_TIMER_TIM].ControlReg = 0;
- prvTimerCtrl.NextTick = 0;
- }
- else if (prvTimerCtrl.NextTick != Timer->TargetTick)
- {
- TIMM0->TIM[SYS_TIMER_TIM].ControlReg = 0;
- clr = TIMM0->TIM[SYS_TIMER_TIM].EOI;
- NowTick = GetSysTick() + 4;
- if (Timer->TargetTick > NowTick)
- {
- PassTick = Timer->TargetTick - NowTick;
- if (PassTick >= 0xfffffffe)
- {
- PassTick = 0xfffffffe;
- }
- }
- else
- {
- PassTick = SYS_TIMER_1US/4;
- }
- prvTimerCtrl.NextTick = Timer->TargetTick;
- ISR_Clear(SYS_TIMER_IRQ);
- TIMM0->TIM[SYS_TIMER_TIM].LoadCount = (uint32_t)PassTick - 1;
- TIMM0->TIM[SYS_TIMER_TIM].ControlReg = TIMER_CONTROL_REG_TIMER_ENABLE|TIMER_CONTROL_REG_TIMER_MODE;
- }
- OS_ExitCritical(Critical);
- }
- static int32_t Timer_AddNew(void *pData, void *pParam)
- {
- Timer_t *OldTimer = (Timer_t *)pData;
- Timer_t *NewTimer = (Timer_t *)pParam;
- if (NewTimer->TargetTick < OldTimer->TargetTick)
- {
- llist_add_tail(&NewTimer->Node, &OldTimer->Node);
- return 1;
- }
- return 0;
- }
- static int32_t Timer_CheckTo(void *pData, void *pParam)
- {
- Timer_t *OldTimer = (Timer_t *)pData;
- if (OldTimer->TargetTick <= prvTimerCtrl.NextTick)
- {
- if (OldTimer->TargetTick < prvTimerCtrl.NextTick)
- {
- DBG("%u", (uint32_t)(prvTimerCtrl.NextTick - OldTimer->TargetTick));
- }
- return 1;
- }
- return 0;
- }
- static void SystemTimerIrqHandler( int32_t Line, void *pData)
- {
- uint32_t Critical;
- uint64_t NowTick;
- Timer_t *Timer;
- volatile uint32_t clr;
- clr = TIMM0->TIM[SYS_TIMER_TIM].EOI;
- TIMM0->TIM[SYS_TIMER_TIM].ControlReg = 0;
- if (prvTimerCtrl.NextTick > GetSysTick())
- {
- // DBG("%u", (uint32_t)(prvTimerCtrl.NextTick - GetSysTick()));
- prvTimerCtrl.NextTick = GetSysTick();
- }
- do
- {
- Critical = OS_EnterCritical();
- Timer = llist_traversal(&prvTimerCtrl.Head, Timer_CheckTo, NULL);
- if (!Timer)
- {
- OS_ExitCritical(Critical);
- break;
- }
- llist_del(&Timer->Node);
- OS_ExitCritical(Critical);
- if (Timer->CallBack)
- {
- Timer->CallBack(Timer, Timer->Param);
- }
- else if (Timer->Handle)
- {
- Task_SendEvent(Timer->Handle, CORE_TIMER_TIMEOUT, Timer->Param, 0, 0);
- }
- if (Timer->AddTick)
- {
- Critical = OS_EnterCritical();
- Timer_Update(Timer, Timer->AddTick, prvTimerCtrl.SleepFlush);
- if (llist_empty(&prvTimerCtrl.Head))
- {
- llist_add_tail(&Timer->Node, &prvTimerCtrl.Head);
- }
- else
- {
- if (!llist_traversal(&prvTimerCtrl.Head, Timer_AddNew, Timer))
- {
- llist_add_tail(&Timer->Node, &prvTimerCtrl.Head);
- }
- }
- OS_ExitCritical(Critical);
- }
- }while(Timer);
- Timer_SetNextIsr();
- }
- static void Timer_Setting(Timer_t *Timer, CBFuncEx_t CB, void *Param, void *NotifyTask)
- {
- memset(Timer, 0, sizeof(Timer_t));
- Timer->CallBack = CB;
- Timer->Param = Param;
- Timer->Handle = NotifyTask;
- Timer->Node.next = NULL;
- Timer->Node.prev = NULL;
- Timer->ID = prvTimerCtrl.IDSn;
- prvTimerCtrl.IDSn++;
- TM_DBG("timer %d set", Timer->ID);
- }
- void Timer_Init(void)
- {
- INIT_LLIST_HEAD(&prvTimerCtrl.Head);
- TIMM0->TIM[SYS_TIMER_TIM].ControlReg = 0;
- ISR_OnOff(SYS_TIMER_IRQ, 0);
- ISR_SetHandler(SYS_TIMER_IRQ, SystemTimerIrqHandler, NULL);
- #ifdef __BUILD_OS__
- ISR_SetPriority(SYS_TIMER_IRQ, IRQ_LOWEST_PRIORITY - 1);
- #else
- ISR_SetPriority(SYS_TIMER_IRQ, SYS_TIMER_IRQ_LEVEL);
- #endif
- ISR_OnOff(SYS_TIMER_IRQ, 1);
- }
- void Timer_Task(void *Param)
- {
- }
- void Timer_WakeupRun(void)
- {
- if (GetSysTick() >= prvTimerCtrl.NextTick)
- {
- ISR_OnOff(SYS_TIMER_IRQ, 0);
- prvTimerCtrl.SleepFlush = 1;
- SystemTimerIrqHandler(SYS_TIMER_IRQ, NULL);
- prvTimerCtrl.SleepFlush = 0;
- ISR_OnOff(SYS_TIMER_IRQ, 1);
- }
- }
- Timer_t * Timer_Create(CBFuncEx_t CB, void *Param, void *NotifyTask)
- {
- #ifdef __BUILD_OS__
- Timer_t *Timer = malloc(sizeof(Timer_t));
- if (Timer)
- {
- Timer_Setting(Timer, CB, Param, NotifyTask);
- }
- return Timer;
- #else
- return NULL;
- #endif
- }
- Timer_t * Timer_GetStatic(uint32_t Sn, CBFuncEx_t CB, void *Param, void *NotifyTask)
- {
- if (Sn < TIMER_SN_MAX)
- {
- Timer_t *Timer = &prvTimer[Sn];
- Timer_Setting(Timer, CB, Param, NotifyTask);
- return Timer;
- }
- else
- {
- return NULL;
- }
- }
- int Timer_Start(Timer_t *Timer, uint64_t Tick, uint8_t IsRepeat)
- {
- uint32_t Critical = OS_EnterCritical();
- llist_del(&Timer->Node);
- if (IsRepeat)
- {
- Timer->AddTick = Tick;
- }
- else
- {
- Timer->AddTick = 0;
- }
- Timer_Update(Timer, Tick, 1);
- if (llist_empty(&prvTimerCtrl.Head))
- {
- llist_add_tail(&Timer->Node, &prvTimerCtrl.Head);
- }
- else
- {
- if (!llist_traversal(&prvTimerCtrl.Head, Timer_AddNew, Timer))
- {
- llist_add_tail(&Timer->Node, &prvTimerCtrl.Head);
- }
- }
- Timer_SetNextIsr();
- OS_ExitCritical(Critical);
- return 0;
- }
- int Timer_StartMS(Timer_t *Timer, uint32_t MS, uint8_t IsRepeat)
- {
- uint64_t Tick = MS;
- Tick *= SYS_TIMER_1MS;
- return Timer_Start(Timer, Tick, IsRepeat);
- }
- int Timer_StartUS(Timer_t *Timer, uint32_t US, uint8_t IsRepeat)
- {
- uint64_t Tick = US;
- Tick *= SYS_TIMER_1US;
- return Timer_Start(Timer, Tick, IsRepeat);
- }
- void Timer_Stop(Timer_t *Timer)
- {
- uint32_t Critical = OS_EnterCritical();
- if (prvTimerCtrl.Head.next == &Timer->Node)
- {
- llist_del(&Timer->Node);
- Timer_SetNextIsr();
- OS_ExitCritical(Critical);
- return;
- }
- else
- {
- llist_del(&Timer->Node);
- }
- OS_ExitCritical(Critical);
- }
- void Timer_Release(Timer_t *Timer)
- {
- Timer_Stop(Timer);
- if ((uint32_t)Timer >= (uint32_t)(&__os_heap_start))
- {
- free(Timer);
- }
- }
- uint32_t Timer_NextToRest(void)
- {
- return TIMM0->TIM[SYS_TIMER_TIM].CurrentValue;
- }
- uint8_t Timer_IsRunning(Timer_t *Timer)
- {
- if (Timer->Node.next && Timer->Node.prev)
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
- static int32_t Timer_PrintInfo(void *pData, void *pParam)
- {
- Timer_t *NewTimer = (Timer_t *)pData;
- TM_DBG("mem 0x%x, id %u, rest tick %llu", NewTimer, NewTimer->ID, NewTimer->TargetTick - prvTimerCtrl.NextTick);
- return 0;
- }
- void Timer_PrintAll(void)
- {
- uint32_t Critical = OS_EnterCritical();
- llist_traversal(&prvTimerCtrl.Head, Timer_PrintInfo, NULL);
- OS_ExitCritical(Critical);
- }
|