/* * Copyright (c) 2013-2017 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" // ==== 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 (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 (os_timer_t *timer) { if (timer->next != NULL) { timer->next->prev = timer->prev; } osRtxInfo.timer.list = timer->next; } // ==== Library functions ==== /// Timer Tick (called each SysTick). void osRtxTimerTick (void) { os_timer_t *timer; osStatus_t status; timer = osRtxInfo.timer.list; if (timer == NULL) { return; } timer->tick--; while ((timer != NULL) && (timer->tick == 0U)) { TimerUnlink(timer); status = osMessageQueuePut(osRtxInfo.timer.mq, &timer->finfo, 0U, 0U); if (status != osOK) { osRtxErrorNotify(osRtxErrorTimerQueueOverflow, timer); } if (timer->type == osRtxTimerPeriodic) { TimerInsert(timer, timer->load); } else { timer->state = osRtxTimerStopped; } timer = osRtxInfo.timer.list; } } /// Timer Thread __NO_RETURN void osRtxTimerThread (void *argument) { os_timer_finfo_t finfo; osStatus_t status; (void) argument; for (;;) { status = osMessageQueueGet(osRtxInfo.timer.mq, &finfo, NULL, osWaitForever); if (status == osOK) { EvrRtxTimerCallback(*(osTimerFunc_t)finfo.fp, finfo.arg); (*(osTimerFunc_t)finfo.fp)(finfo.arg); } } } // ==== Service Calls ==== // Service Calls definitions SVC0_4M(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) /// Create and Initialize a timer. /// \note API identical to osTimerNew osTimerId_t svcRtxTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr) { os_timer_t *timer; uint8_t flags; const char *name; // Create common timer message queue if not yet active if (osRtxInfo.timer.mq == NULL) { osRtxInfo.timer.mq = svcRtxMessageQueueNew(osRtxConfig.timer_mq_mcnt, sizeof(os_timer_finfo_t), osRtxConfig.timer_mq_attr); if (osRtxInfo.timer.mq == NULL) { EvrRtxTimerError(NULL, osErrorResource); return NULL; } } // Create common timer thread if not yet active if (osRtxInfo.timer.thread == NULL) { osRtxInfo.timer.thread = svcRtxThreadNew(osRtxTimerThread, NULL, osRtxConfig.timer_thread_attr); if (osRtxInfo.timer.thread == NULL) { EvrRtxTimerError(NULL, osErrorResource); return NULL; } } // Check parameters if ((func == NULL) || ((type != osTimerOnce) && (type != osTimerPeriodic))) { EvrRtxTimerError(NULL, osErrorParameter); return NULL; } // Process attributes if (attr != NULL) { name = attr->name; timer = attr->cb_mem; if (timer != NULL) { if (((uint32_t)timer & 3U) || (attr->cb_size < sizeof(os_timer_t))) { EvrRtxTimerError(NULL, osRtxErrorInvalidControlBlock); return NULL; } } else { if (attr->cb_size != 0U) { EvrRtxTimerError(NULL, osRtxErrorInvalidControlBlock); return NULL; } } } else { name = NULL; timer = NULL; } // Allocate object memory if not provided if (timer == NULL) { if (osRtxInfo.mpi.timer != NULL) { timer = osRtxMemoryPoolAlloc(osRtxInfo.mpi.timer); } else { timer = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_timer_t), 1U); } if (timer == NULL) { EvrRtxTimerError(NULL, osErrorNoMemory); return NULL; } flags = osRtxFlagSystemObject; } else { flags = 0U; } // Initialize control block timer->id = osRtxIdTimer; timer->state = osRtxTimerStopped; timer->flags = flags; timer->type = (uint8_t)type; timer->name = name; timer->prev = NULL; timer->next = NULL; timer->tick = 0U; timer->load = 0U; timer->finfo.fp = (void *)func; timer->finfo.arg = argument; EvrRtxTimerCreated(timer); return timer; } /// Get name of a timer. /// \note API identical to osTimerGetName const char *svcRtxTimerGetName (osTimerId_t timer_id) { os_timer_t *timer = (os_timer_t *)timer_id; // Check parameters if ((timer == NULL) || (timer->id != osRtxIdTimer)) { EvrRtxTimerGetName(timer, NULL); return NULL; } // Check object state if (timer->state == osRtxObjectInactive) { EvrRtxTimerGetName(timer, NULL); return NULL; } EvrRtxTimerGetName(timer, timer->name); return timer->name; } /// Start or restart a timer. /// \note API identical to osTimerStart osStatus_t svcRtxTimerStart (osTimerId_t timer_id, uint32_t ticks) { os_timer_t *timer = (os_timer_t *)timer_id; // Check parameters if ((timer == NULL) || (timer->id != osRtxIdTimer) || (ticks == 0U)) { EvrRtxTimerError(timer, osErrorParameter); return osErrorParameter; } // Check object state switch (timer->state) { case osRtxTimerStopped: timer->state = osRtxTimerRunning; timer->load = ticks; break; case osRtxTimerRunning: TimerRemove(timer); break; case osRtxTimerInactive: default: EvrRtxTimerError(timer, osErrorResource); return osErrorResource; } TimerInsert(timer, ticks); EvrRtxTimerStarted(timer); return osOK; } /// Stop a timer. /// \note API identical to osTimerStop osStatus_t svcRtxTimerStop (osTimerId_t timer_id) { os_timer_t *timer = (os_timer_t *)timer_id; // Check parameters if ((timer == NULL) || (timer->id != osRtxIdTimer)) { EvrRtxTimerError(timer, osErrorParameter); return osErrorParameter; } // Check object state if (timer->state != osRtxTimerRunning) { EvrRtxTimerError(timer, osErrorResource); return osErrorResource; } timer->state = osRtxTimerStopped; TimerRemove(timer); EvrRtxTimerStopped(timer); return osOK; } /// Check if a timer is running. /// \note API identical to osTimerIsRunning uint32_t svcRtxTimerIsRunning (osTimerId_t timer_id) { os_timer_t *timer = (os_timer_t *)timer_id; // Check parameters if ((timer == NULL) || (timer->id != osRtxIdTimer)) { EvrRtxTimerIsRunning(timer, 0U); return 0U; } // Check object state if (timer->state == osRtxTimerRunning) { EvrRtxTimerIsRunning(timer, 1U); return 1U; } EvrRtxTimerIsRunning(timer, 0U); return 0U; } /// Delete a timer. /// \note API identical to osTimerDelete osStatus_t svcRtxTimerDelete (osTimerId_t timer_id) { os_timer_t *timer = (os_timer_t *)timer_id; // Check parameters if ((timer == NULL) || (timer->id != osRtxIdTimer)) { EvrRtxTimerError(timer, osErrorParameter); return osErrorParameter; } // Check object state switch (timer->state) { case osRtxTimerStopped: break; case osRtxTimerRunning: TimerRemove(timer); break; case osRtxTimerInactive: default: EvrRtxTimerError(timer, osErrorResource); return osErrorResource; } // Mark object as inactive timer->state = osRtxTimerInactive; // Free object memory if (timer->flags & osRtxFlagSystemObject) { if (osRtxInfo.mpi.timer != NULL) { osRtxMemoryPoolFree(osRtxInfo.mpi.timer, timer); } else { osRtxMemoryFree(osRtxInfo.mem.common, timer); } } EvrRtxTimerDestroyed(timer); return osOK; } // ==== Public API ==== /// Create and Initialize a timer. osTimerId_t osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr) { EvrRtxTimerNew(func, type, argument, attr); if (IS_IRQ_MODE() || IS_IRQ_MASKED()) { EvrRtxTimerError(NULL, osErrorISR); return NULL; } return __svcTimerNew(func, type, argument, attr); } /// Get name of a timer. const char *osTimerGetName (osTimerId_t timer_id) { if (IS_IRQ_MODE() || IS_IRQ_MASKED()) { EvrRtxTimerGetName(timer_id, NULL); return NULL; } return __svcTimerGetName(timer_id); } /// Start or restart a timer. osStatus_t osTimerStart (osTimerId_t timer_id, uint32_t ticks) { EvrRtxTimerStart(timer_id, ticks); if (IS_IRQ_MODE() || IS_IRQ_MASKED()) { EvrRtxTimerError(timer_id, osErrorISR); return osErrorISR; } return __svcTimerStart(timer_id, ticks); } /// Stop a timer. osStatus_t osTimerStop (osTimerId_t timer_id) { EvrRtxTimerStop(timer_id); if (IS_IRQ_MODE() || IS_IRQ_MASKED()) { EvrRtxTimerError(timer_id, osErrorISR); return osErrorISR; } return __svcTimerStop(timer_id); } /// Check if a timer is running. uint32_t osTimerIsRunning (osTimerId_t timer_id) { if (IS_IRQ_MODE() || IS_IRQ_MASKED()) { EvrRtxTimerIsRunning(timer_id, 0U); return 0U; } return __svcTimerIsRunning(timer_id); } /// Delete a timer. osStatus_t osTimerDelete (osTimerId_t timer_id) { EvrRtxTimerDelete(timer_id); if (IS_IRQ_MODE() || IS_IRQ_MASKED()) { EvrRtxTimerError(timer_id, osErrorISR); return osErrorISR; } return __svcTimerDelete(timer_id); }