| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631 |
- /*
- * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the License); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an AS IS BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * -----------------------------------------------------------------------------
- *
- * Project: CMSIS-RTOS RTX
- * Title: Timer functions
- *
- * -----------------------------------------------------------------------------
- */
- #include "rtx_lib.h"
- // OS Runtime Object Memory Usage
- #ifdef RTX_OBJ_MEM_USAGE
- osRtxObjectMemUsage_t osRtxTimerMemUsage \
- __attribute__((section(".data.os.timer.obj"))) =
- { 0U, 0U, 0U };
- #endif
- // ==== Helper functions ====
- /// Insert Timer into the Timer List sorted by Time.
- /// \param[in] timer timer object.
- /// \param[in] tick timer tick.
- static void TimerInsert (os_timer_t *timer, uint32_t tick) {
- os_timer_t *prev, *next;
- prev = NULL;
- next = osRtxInfo.timer.list;
- while ((next != NULL) && (next->tick <= tick)) {
- tick -= next->tick;
- prev = next;
- next = next->next;
- }
- timer->tick = tick;
- timer->prev = prev;
- timer->next = next;
- if (next != NULL) {
- next->tick -= timer->tick;
- next->prev = timer;
- }
- if (prev != NULL) {
- prev->next = timer;
- } else {
- osRtxInfo.timer.list = timer;
- }
- }
- /// Remove Timer from the Timer List.
- /// \param[in] timer timer object.
- static void TimerRemove (const os_timer_t *timer) {
- if (timer->next != NULL) {
- timer->next->tick += timer->tick;
- timer->next->prev = timer->prev;
- }
- if (timer->prev != NULL) {
- timer->prev->next = timer->next;
- } else {
- osRtxInfo.timer.list = timer->next;
- }
- }
- /// Unlink Timer from the Timer List Head.
- /// \param[in] timer timer object.
- static void TimerUnlink (const os_timer_t *timer) {
- if (timer->next != NULL) {
- timer->next->prev = timer->prev;
- }
- osRtxInfo.timer.list = timer->next;
- }
- /// Verify that Timer object pointer is valid.
- /// \param[in] timer timer object.
- /// \return true - valid, false - invalid.
- static bool_t IsTimerPtrValid (const os_timer_t *timer) {
- #ifdef RTX_OBJ_PTR_CHECK
- //lint --e{923} --e{9078} "cast from pointer to unsigned int" [MISRA Note 7]
- uint32_t cb_start = (uint32_t)&__os_timer_cb_start__;
- uint32_t cb_length = (uint32_t)&__os_timer_cb_length__;
- // Check the section boundaries
- if (((uint32_t)timer - cb_start) >= cb_length) {
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return FALSE;
- }
- // Check the object alignment
- if ((((uint32_t)timer - cb_start) % sizeof(os_timer_t)) != 0U) {
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return FALSE;
- }
- #else
- // Check NULL pointer
- if (timer == NULL) {
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return FALSE;
- }
- #endif
- return TRUE;
- }
- // ==== Library functions ====
- /// Timer Tick (called each SysTick).
- static void osRtxTimerTick (void) {
- os_thread_t *thread_running;
- os_timer_t *timer;
- osStatus_t status;
- timer = osRtxInfo.timer.list;
- if (timer == NULL) {
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return;
- }
- thread_running = osRtxThreadGetRunning();
- timer->tick--;
- while ((timer != NULL) && (timer->tick == 0U)) {
- TimerUnlink(timer);
- status = osMessageQueuePut(osRtxInfo.timer.mq, &timer->finfo, 0U, 0U);
- if (status != osOK) {
- const os_thread_t *thread = osRtxThreadGetRunning();
- osRtxThreadSetRunning(osRtxInfo.thread.run.next);
- (void)osRtxKernelErrorNotify(osRtxErrorTimerQueueOverflow, timer);
- if (osRtxThreadGetRunning() == NULL) {
- if (thread_running == thread) {
- thread_running = NULL;
- }
- }
- }
- if ((timer->attr & osRtxTimerPeriodic) != 0U) {
- TimerInsert(timer, timer->load);
- } else {
- timer->state = osRtxTimerStopped;
- }
- timer = osRtxInfo.timer.list;
- }
- osRtxThreadSetRunning(thread_running);
- }
- /// Setup Timer Thread objects.
- //lint -esym(714,osRtxTimerSetup) "Referenced from library configuration"
- //lint -esym(759,osRtxTimerSetup) "Prototype in header"
- //lint -esym(765,osRtxTimerSetup) "Global scope"
- int32_t osRtxTimerSetup (void) {
- int32_t ret = -1;
- if (osRtxMessageQueueTimerSetup() == 0) {
- osRtxInfo.timer.tick = osRtxTimerTick;
- ret = 0;
- }
- return ret;
- }
- /// Timer Thread
- //lint -esym(714,osRtxTimerThread) "Referenced from library configuration"
- //lint -esym(759,osRtxTimerThread) "Prototype in header"
- //lint -esym(765,osRtxTimerThread) "Global scope"
- __NO_RETURN void osRtxTimerThread (void *argument) {
- os_timer_finfo_t finfo;
- osStatus_t status;
- osMessageQueueId_t mq = (osMessageQueueId_t)argument;
- for (;;) {
- //lint -e{934} "Taking address of near auto variable"
- status = osMessageQueueGet(mq, &finfo, NULL, osWaitForever);
- if (status == osOK) {
- EvrRtxTimerCallback(finfo.func, finfo.arg);
- (finfo.func)(finfo.arg);
- }
- }
- }
- /// Destroy a Timer object.
- /// \param[in] timer timer object.
- static void osRtxTimerDestroy (os_timer_t *timer) {
- // Mark object as inactive and invalid
- timer->state = osRtxTimerInactive;
- timer->id = osRtxIdInvalid;
- // Free object memory
- if ((timer->flags & osRtxFlagSystemObject) != 0U) {
- #ifdef RTX_OBJ_PTR_CHECK
- (void)osRtxMemoryPoolFree(osRtxInfo.mpi.timer, timer);
- #else
- if (osRtxInfo.mpi.timer != NULL) {
- (void)osRtxMemoryPoolFree(osRtxInfo.mpi.timer, timer);
- } else {
- (void)osRtxMemoryFree(osRtxInfo.mem.common, timer);
- }
- #endif
- #ifdef RTX_OBJ_MEM_USAGE
- osRtxTimerMemUsage.cnt_free++;
- #endif
- }
- EvrRtxTimerDestroyed(timer);
- }
- #ifdef RTX_SAFETY_CLASS
- /// Delete a Timer safety class.
- /// \param[in] safety_class safety class.
- /// \param[in] mode safety mode.
- void osRtxTimerDeleteClass (uint32_t safety_class, uint32_t mode) {
- os_timer_t *timer;
- uint32_t length;
- //lint --e{923} --e{9078} "cast from pointer to unsigned int" [MISRA Note 7]
- timer = (os_timer_t *)(uint32_t)&__os_timer_cb_start__;
- length = (uint32_t)&__os_timer_cb_length__;
- while (length >= sizeof(os_timer_t)) {
- if ( (timer->id == osRtxIdTimer) &&
- ((((mode & osSafetyWithSameClass) != 0U) &&
- ((timer->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
- (((mode & osSafetyWithLowerClass) != 0U) &&
- ((timer->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class)))) {
- if (timer->state == osRtxTimerRunning) {
- TimerRemove(timer);
- }
- osRtxTimerDestroy(timer);
- }
- length -= sizeof(os_timer_t);
- timer++;
- }
- }
- #endif
- // ==== Service Calls ====
- /// Create and Initialize a timer.
- /// \note API identical to osTimerNew
- static osTimerId_t svcRtxTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr) {
- os_timer_t *timer;
- #ifdef RTX_SAFETY_CLASS
- const os_thread_t *thread = osRtxThreadGetRunning();
- uint32_t attr_bits;
- #endif
- uint8_t flags;
- const char *name;
- // Check parameters
- if ((func == NULL) || ((type != osTimerOnce) && (type != osTimerPeriodic))) {
- EvrRtxTimerError(NULL, (int32_t)osErrorParameter);
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return NULL;
- }
- // Process attributes
- if (attr != NULL) {
- name = attr->name;
- #ifdef RTX_SAFETY_CLASS
- attr_bits = attr->attr_bits;
- #endif
- //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
- timer = attr->cb_mem;
- #ifdef RTX_SAFETY_CLASS
- if ((attr_bits & osSafetyClass_Valid) != 0U) {
- if ((thread != NULL) &&
- ((thread->attr >> osRtxAttrClass_Pos) <
- (uint8_t)((attr_bits & osSafetyClass_Msk) >> osSafetyClass_Pos))) {
- EvrRtxTimerError(NULL, (int32_t)osErrorSafetyClass);
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return NULL;
- }
- }
- #endif
- if (timer != NULL) {
- if (!IsTimerPtrValid(timer) || (attr->cb_size != sizeof(os_timer_t))) {
- EvrRtxTimerError(NULL, osRtxErrorInvalidControlBlock);
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return NULL;
- }
- } else {
- if (attr->cb_size != 0U) {
- EvrRtxTimerError(NULL, osRtxErrorInvalidControlBlock);
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return NULL;
- }
- }
- } else {
- name = NULL;
- #ifdef RTX_SAFETY_CLASS
- attr_bits = 0U;
- #endif
- timer = NULL;
- }
- // Allocate object memory if not provided
- if (timer == NULL) {
- if (osRtxInfo.mpi.timer != NULL) {
- //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
- timer = osRtxMemoryPoolAlloc(osRtxInfo.mpi.timer);
- #ifndef RTX_OBJ_PTR_CHECK
- } else {
- //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
- timer = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_timer_t), 1U);
- #endif
- }
- #ifdef RTX_OBJ_MEM_USAGE
- if (timer != NULL) {
- uint32_t used;
- osRtxTimerMemUsage.cnt_alloc++;
- used = osRtxTimerMemUsage.cnt_alloc - osRtxTimerMemUsage.cnt_free;
- if (osRtxTimerMemUsage.max_used < used) {
- osRtxTimerMemUsage.max_used = used;
- }
- }
- #endif
- flags = osRtxFlagSystemObject;
- } else {
- flags = 0U;
- }
- if (timer != NULL) {
- // Initialize control block
- timer->id = osRtxIdTimer;
- timer->state = osRtxTimerStopped;
- timer->flags = flags;
- if (type == osTimerPeriodic) {
- timer->attr = osRtxTimerPeriodic;
- } else {
- timer->attr = 0U;
- }
- timer->name = name;
- timer->prev = NULL;
- timer->next = NULL;
- timer->tick = 0U;
- timer->load = 0U;
- timer->finfo.func = func;
- timer->finfo.arg = argument;
- #ifdef RTX_SAFETY_CLASS
- if ((attr_bits & osSafetyClass_Valid) != 0U) {
- timer->attr |= (uint8_t)((attr_bits & osSafetyClass_Msk) >>
- (osSafetyClass_Pos - osRtxAttrClass_Pos));
- } else {
- // Inherit safety class from the running thread
- if (thread != NULL) {
- timer->attr |= (uint8_t)(thread->attr & osRtxAttrClass_Msk);
- }
- }
- #endif
- EvrRtxTimerCreated(timer, timer->name);
- } else {
- EvrRtxTimerError(NULL, (int32_t)osErrorNoMemory);
- }
- return timer;
- }
- /// Get name of a timer.
- /// \note API identical to osTimerGetName
- static const char *svcRtxTimerGetName (osTimerId_t timer_id) {
- os_timer_t *timer = osRtxTimerId(timer_id);
- // Check parameters
- if (!IsTimerPtrValid(timer) || (timer->id != osRtxIdTimer)) {
- EvrRtxTimerGetName(timer, NULL);
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return NULL;
- }
- EvrRtxTimerGetName(timer, timer->name);
- return timer->name;
- }
- /// Start or restart a timer.
- /// \note API identical to osTimerStart
- static osStatus_t svcRtxTimerStart (osTimerId_t timer_id, uint32_t ticks) {
- os_timer_t *timer = osRtxTimerId(timer_id);
- #ifdef RTX_SAFETY_CLASS
- const os_thread_t *thread;
- #endif
- // Check parameters
- if (!IsTimerPtrValid(timer) || (timer->id != osRtxIdTimer) || (ticks == 0U)) {
- EvrRtxTimerError(timer, (int32_t)osErrorParameter);
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return osErrorParameter;
- }
- #ifdef RTX_SAFETY_CLASS
- // Check running thread safety class
- thread = osRtxThreadGetRunning();
- if ((thread != NULL) &&
- ((thread->attr >> osRtxAttrClass_Pos) < (timer->attr >> osRtxAttrClass_Pos))) {
- EvrRtxTimerError(timer, (int32_t)osErrorSafetyClass);
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return osErrorSafetyClass;
- }
- #endif
- if (timer->state == osRtxTimerRunning) {
- timer->load = ticks;
- TimerRemove(timer);
- } else {
- if (osRtxInfo.timer.tick == NULL) {
- EvrRtxTimerError(timer, (int32_t)osErrorResource);
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return osErrorResource;
- } else {
- timer->state = osRtxTimerRunning;
- timer->load = ticks;
- }
- }
- TimerInsert(timer, ticks);
- EvrRtxTimerStarted(timer);
- return osOK;
- }
- /// Stop a timer.
- /// \note API identical to osTimerStop
- static osStatus_t svcRtxTimerStop (osTimerId_t timer_id) {
- os_timer_t *timer = osRtxTimerId(timer_id);
- #ifdef RTX_SAFETY_CLASS
- const os_thread_t *thread;
- #endif
- // Check parameters
- if (!IsTimerPtrValid(timer) || (timer->id != osRtxIdTimer)) {
- EvrRtxTimerError(timer, (int32_t)osErrorParameter);
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return osErrorParameter;
- }
- #ifdef RTX_SAFETY_CLASS
- // Check running thread safety class
- thread = osRtxThreadGetRunning();
- if ((thread != NULL) &&
- ((thread->attr >> osRtxAttrClass_Pos) < (timer->attr >> osRtxAttrClass_Pos))) {
- EvrRtxTimerError(timer, (int32_t)osErrorSafetyClass);
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return osErrorSafetyClass;
- }
- #endif
- // Check object state
- if (timer->state != osRtxTimerRunning) {
- EvrRtxTimerError(timer, (int32_t)osErrorResource);
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return osErrorResource;
- }
- timer->state = osRtxTimerStopped;
- TimerRemove(timer);
- EvrRtxTimerStopped(timer);
- return osOK;
- }
- /// Check if a timer is running.
- /// \note API identical to osTimerIsRunning
- static uint32_t svcRtxTimerIsRunning (osTimerId_t timer_id) {
- os_timer_t *timer = osRtxTimerId(timer_id);
- uint32_t is_running;
- // Check parameters
- if (!IsTimerPtrValid(timer) || (timer->id != osRtxIdTimer)) {
- EvrRtxTimerIsRunning(timer, 0U);
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return 0U;
- }
- if (timer->state == osRtxTimerRunning) {
- EvrRtxTimerIsRunning(timer, 1U);
- is_running = 1U;
- } else {
- EvrRtxTimerIsRunning(timer, 0U);
- is_running = 0;
- }
- return is_running;
- }
- /// Delete a timer.
- /// \note API identical to osTimerDelete
- static osStatus_t svcRtxTimerDelete (osTimerId_t timer_id) {
- os_timer_t *timer = osRtxTimerId(timer_id);
- #ifdef RTX_SAFETY_CLASS
- const os_thread_t *thread;
- #endif
- // Check parameters
- if (!IsTimerPtrValid(timer) || (timer->id != osRtxIdTimer)) {
- EvrRtxTimerError(timer, (int32_t)osErrorParameter);
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return osErrorParameter;
- }
- #ifdef RTX_SAFETY_CLASS
- // Check running thread safety class
- thread = osRtxThreadGetRunning();
- if ((thread != NULL) &&
- ((thread->attr >> osRtxAttrClass_Pos) < (timer->attr >> osRtxAttrClass_Pos))) {
- EvrRtxTimerError(timer, (int32_t)osErrorSafetyClass);
- //lint -e{904} "Return statement before end of function" [MISRA Note 1]
- return osErrorSafetyClass;
- }
- #endif
- if (timer->state == osRtxTimerRunning) {
- TimerRemove(timer);
- }
- osRtxTimerDestroy(timer);
- return osOK;
- }
- // Service Calls definitions
- //lint ++flb "Library Begin" [MISRA Note 11]
- SVC0_4(TimerNew, osTimerId_t, osTimerFunc_t, osTimerType_t, void *, const osTimerAttr_t *)
- SVC0_1(TimerGetName, const char *, osTimerId_t)
- SVC0_2(TimerStart, osStatus_t, osTimerId_t, uint32_t)
- SVC0_1(TimerStop, osStatus_t, osTimerId_t)
- SVC0_1(TimerIsRunning, uint32_t, osTimerId_t)
- SVC0_1(TimerDelete, osStatus_t, osTimerId_t)
- //lint --flb "Library End"
- // ==== Public API ====
- /// Create and Initialize a timer.
- osTimerId_t osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr) {
- osTimerId_t timer_id;
- EvrRtxTimerNew(func, type, argument, attr);
- if (IsException() || IsIrqMasked()) {
- EvrRtxTimerError(NULL, (int32_t)osErrorISR);
- timer_id = NULL;
- } else {
- timer_id = __svcTimerNew(func, type, argument, attr);
- }
- return timer_id;
- }
- /// Get name of a timer.
- const char *osTimerGetName (osTimerId_t timer_id) {
- const char *name;
- if (IsException() || IsIrqMasked()) {
- name = svcRtxTimerGetName(timer_id);
- } else {
- name = __svcTimerGetName(timer_id);
- }
- return name;
- }
- /// Start or restart a timer.
- osStatus_t osTimerStart (osTimerId_t timer_id, uint32_t ticks) {
- osStatus_t status;
- EvrRtxTimerStart(timer_id, ticks);
- if (IsException() || IsIrqMasked()) {
- EvrRtxTimerError(timer_id, (int32_t)osErrorISR);
- status = osErrorISR;
- } else {
- status = __svcTimerStart(timer_id, ticks);
- }
- return status;
- }
- /// Stop a timer.
- osStatus_t osTimerStop (osTimerId_t timer_id) {
- osStatus_t status;
- EvrRtxTimerStop(timer_id);
- if (IsException() || IsIrqMasked()) {
- EvrRtxTimerError(timer_id, (int32_t)osErrorISR);
- status = osErrorISR;
- } else {
- status = __svcTimerStop(timer_id);
- }
- return status;
- }
- /// Check if a timer is running.
- uint32_t osTimerIsRunning (osTimerId_t timer_id) {
- uint32_t is_running;
- if (IsException() || IsIrqMasked()) {
- EvrRtxTimerIsRunning(timer_id, 0U);
- is_running = 0U;
- } else {
- is_running = __svcTimerIsRunning(timer_id);
- }
- return is_running;
- }
- /// Delete a timer.
- osStatus_t osTimerDelete (osTimerId_t timer_id) {
- osStatus_t status;
- EvrRtxTimerDelete(timer_id);
- if (IsException() || IsIrqMasked()) {
- EvrRtxTimerError(timer_id, (int32_t)osErrorISR);
- status = osErrorISR;
- } else {
- status = __svcTimerDelete(timer_id);
- }
- return status;
- }
|