1 /* --------------------------------------------------------------------------
2 * Copyright (c) 2013-2024 Arm Limited. All rights reserved.
4 * SPDX-License-Identifier: Apache-2.0
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 * Purpose: CMSIS RTOS2 wrapper for FreeRTOS
21 *---------------------------------------------------------------------------*/
25 #include "cmsis_os2.h" // ::CMSIS:RTOS2
26 #include "cmsis_compiler.h" // Compiler agnostic definitions
27 #include "os_tick.h" // OS Tick API
29 #include "FreeRTOS.h" // ARM.FreeRTOS::RTOS:Core
30 #include "task.h" // ARM.FreeRTOS::RTOS:Core
31 #include "event_groups.h" // ARM.FreeRTOS::RTOS:Event Groups
32 #include "semphr.h" // ARM.FreeRTOS::RTOS:Core
33 #include "timers.h" // ARM.FreeRTOS::RTOS:Timers
35 #include "freertos_mpool.h" // osMemoryPool definitions
36 #include "freertos_os2.h" // Configuration check and setup
38 /*---------------------------------------------------------------------------*/
39 #ifndef __ARM_ARCH_6M__
40 #define __ARM_ARCH_6M__ 0
42 #ifndef __ARM_ARCH_7M__
43 #define __ARM_ARCH_7M__ 0
45 #ifndef __ARM_ARCH_7EM__
46 #define __ARM_ARCH_7EM__ 0
48 #ifndef __ARM_ARCH_8M_MAIN__
49 #define __ARM_ARCH_8M_MAIN__ 0
51 #ifndef __ARM_ARCH_7A__
52 #define __ARM_ARCH_7A__ 0
55 #if ((__ARM_ARCH_7M__ == 1U) || \
56 (__ARM_ARCH_7EM__ == 1U) || \
57 (__ARM_ARCH_8M_MAIN__ == 1U))
58 #define IS_IRQ_MASKED() ((__get_PRIMASK() != 0U) || (__get_BASEPRI() != 0U))
59 #elif (__ARM_ARCH_6M__ == 1U)
60 #define IS_IRQ_MASKED() (__get_PRIMASK() != 0U)
61 #elif (__ARM_ARCH_7A__ == 1U)
63 #define CPSR_MASKBIT_I 0x80U
65 #define IS_IRQ_MASKED() ((__get_CPSR() & CPSR_MASKBIT_I) != 0U)
67 #define IS_IRQ_MASKED() (__get_PRIMASK() != 0U)
70 #if (__ARM_ARCH_7A__ == 1U)
71 /* CPSR mode bitmasks */
72 #define CPSR_MODE_USER 0x10U
73 #define CPSR_MODE_SYSTEM 0x1FU
75 #define IS_IRQ_MODE() ((__get_mode() != CPSR_MODE_USER) && (__get_mode() != CPSR_MODE_SYSTEM))
77 #define IS_IRQ_MODE() (__get_IPSR() != 0U)
81 #define MAX_BITS_TASK_NOTIFY 31U
82 #define MAX_BITS_EVENT_GROUPS 24U
84 #define THREAD_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_TASK_NOTIFY) - 1U))
85 #define EVENT_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_EVENT_GROUPS) - 1U))
87 /* Kernel version and identification string definition (major.minor.rev: mmnnnrrrr dec) */
88 #define KERNEL_VERSION (((uint32_t)tskKERNEL_VERSION_MAJOR * 10000000UL) | \
89 ((uint32_t)tskKERNEL_VERSION_MINOR * 10000UL) | \
90 ((uint32_t)tskKERNEL_VERSION_BUILD * 1UL))
92 #define KERNEL_ID ("FreeRTOS " tskKERNEL_VERSION_NUMBER)
94 /* Timer callback information structure definition */
100 /* Kernel initialization state */
101 static osKernelState_t KernelState = osKernelInactive;
104 Heap region definition used by heap_5 variant
106 Define configAPPLICATION_ALLOCATED_HEAP as nonzero value in FreeRTOSConfig.h if
107 heap regions are already defined and vPortDefineHeapRegions is called in application.
109 Otherwise vPortDefineHeapRegions will be called by osKernelInitialize using
110 definition configHEAP_5_REGIONS as parameter. Overriding configHEAP_5_REGIONS
111 is possible by defining it globally or in FreeRTOSConfig.h.
113 #if defined(USE_FreeRTOS_HEAP_5)
114 #if (configAPPLICATION_ALLOCATED_HEAP == 0)
116 FreeRTOS heap is not defined by the application.
117 Single region of size configTOTAL_HEAP_SIZE (defined in FreeRTOSConfig.h)
118 is provided by default. Define configHEAP_5_REGIONS to provide custom
121 #define HEAP_5_REGION_SETUP 1
123 #ifndef configHEAP_5_REGIONS
124 #define configHEAP_5_REGIONS xHeapRegions
126 static uint8_t ucHeap[configTOTAL_HEAP_SIZE];
128 static HeapRegion_t xHeapRegions[] = {
129 { ucHeap, configTOTAL_HEAP_SIZE },
133 /* Global definition is provided to override default heap array */
134 extern HeapRegion_t configHEAP_5_REGIONS[];
138 The application already defined the array used for the FreeRTOS heap and
139 called vPortDefineHeapRegions to initialize heap.
141 #define HEAP_5_REGION_SETUP 0
142 #endif /* configAPPLICATION_ALLOCATED_HEAP */
143 #endif /* USE_FreeRTOS_HEAP_5 */
146 #undef SysTick_Handler
148 /* CMSIS SysTick interrupt handler prototype */
149 extern void SysTick_Handler (void);
150 /* FreeRTOS tick timer interrupt handler prototype */
151 extern void xPortSysTickHandler (void);
154 SysTick handler implementation that also clears overflow flag.
156 void SysTick_Handler (void) {
157 #if (configUSE_TICKLESS_IDLE == 0)
158 /* Clear overflow flag */
162 if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
163 /* Call tick handler */
164 xPortSysTickHandler();
170 Determine if CPU executes from interrupt context or if interrupts are masked.
172 __STATIC_INLINE uint32_t IRQ_Context (void) {
179 /* Called from interrupt context */
183 /* Get FreeRTOS scheduler state */
184 state = xTaskGetSchedulerState();
186 if (state != taskSCHEDULER_NOT_STARTED) {
187 /* Scheduler was started */
188 if (IS_IRQ_MASKED()) {
189 /* Interrupts are masked */
195 /* Return context, 0: thread context, 1: IRQ context */
200 /* ==== Kernel Management Functions ==== */
203 Initialize the RTOS Kernel.
205 osStatus_t osKernelInitialize (void) {
209 if (IRQ_Context() != 0U) {
213 state = xTaskGetSchedulerState();
215 /* Initialize if scheduler not started and not initialized before */
216 if ((state == taskSCHEDULER_NOT_STARTED) && (KernelState == osKernelInactive)) {
217 #if defined(USE_TRACE_EVENT_RECORDER)
218 /* Initialize the trace macro debugging output channel */
219 EvrFreeRTOSSetup(0U);
221 #if defined(USE_FreeRTOS_HEAP_5) && (HEAP_5_REGION_SETUP == 1)
222 /* Initialize the memory regions when using heap_5 variant */
223 vPortDefineHeapRegions (configHEAP_5_REGIONS);
225 KernelState = osKernelReady;
232 /* Return execution status */
237 Get RTOS Kernel Information.
239 osStatus_t osKernelGetInfo (osVersion_t *version, char *id_buf, uint32_t id_size) {
241 if (version != NULL) {
242 /* Version encoding is major.minor.rev: mmnnnrrrr dec */
243 version->api = KERNEL_VERSION;
244 version->kernel = KERNEL_VERSION;
247 if ((id_buf != NULL) && (id_size != 0U)) {
248 /* Buffer for retrieving identification string is provided */
249 if (id_size > sizeof(KERNEL_ID)) {
250 id_size = sizeof(KERNEL_ID);
252 /* Copy kernel identification string into provided buffer */
253 memcpy(id_buf, KERNEL_ID, id_size);
256 /* Return execution status */
261 Get the current RTOS Kernel state.
263 osKernelState_t osKernelGetState (void) {
264 osKernelState_t state;
266 switch (xTaskGetSchedulerState()) {
267 case taskSCHEDULER_RUNNING:
268 state = osKernelRunning;
271 case taskSCHEDULER_SUSPENDED:
272 state = osKernelLocked;
275 case taskSCHEDULER_NOT_STARTED:
277 if (KernelState == osKernelReady) {
278 /* Ready, osKernelInitialize was already called */
279 state = osKernelReady;
281 /* Not initialized */
282 state = osKernelInactive;
287 /* Return current state */
292 Start the RTOS Kernel scheduler.
294 osStatus_t osKernelStart (void) {
298 if (IRQ_Context() != 0U) {
302 state = xTaskGetSchedulerState();
304 /* Start scheduler if initialized and not started before */
305 if ((state == taskSCHEDULER_NOT_STARTED) && (KernelState == osKernelReady)) {
306 /* Change state to ensure correct API flow */
307 KernelState = osKernelRunning;
308 /* Start the kernel scheduler */
309 vTaskStartScheduler();
316 /* Return execution status */
321 Lock the RTOS Kernel scheduler.
323 int32_t osKernelLock (void) {
326 if (IRQ_Context() != 0U) {
327 lock = (int32_t)osErrorISR;
330 switch (xTaskGetSchedulerState()) {
331 case taskSCHEDULER_SUSPENDED:
335 case taskSCHEDULER_RUNNING:
340 case taskSCHEDULER_NOT_STARTED:
342 lock = (int32_t)osError;
347 /* Return previous lock state */
352 Unlock the RTOS Kernel scheduler.
354 int32_t osKernelUnlock (void) {
357 if (IRQ_Context() != 0U) {
358 lock = (int32_t)osErrorISR;
361 switch (xTaskGetSchedulerState()) {
362 case taskSCHEDULER_SUSPENDED:
365 if (xTaskResumeAll() != pdTRUE) {
366 if (xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED) {
367 lock = (int32_t)osError;
372 case taskSCHEDULER_RUNNING:
376 case taskSCHEDULER_NOT_STARTED:
378 lock = (int32_t)osError;
383 /* Return previous lock state */
388 Restore the RTOS Kernel scheduler lock state.
390 int32_t osKernelRestoreLock (int32_t lock) {
392 if (IRQ_Context() != 0U) {
393 lock = (int32_t)osErrorISR;
396 switch (xTaskGetSchedulerState()) {
397 case taskSCHEDULER_SUSPENDED:
399 if (xTaskResumeAll() != pdTRUE) {
400 lock = (int32_t)osError;
405 lock = (int32_t)osError;
410 case taskSCHEDULER_RUNNING:
416 lock = (int32_t)osError;
421 case taskSCHEDULER_NOT_STARTED:
423 lock = (int32_t)osError;
428 /* Return new lock state */
433 Get the RTOS kernel tick count.
435 uint32_t osKernelGetTickCount (void) {
438 if (IRQ_Context() != 0U) {
439 ticks = xTaskGetTickCountFromISR();
441 ticks = xTaskGetTickCount();
444 /* Return kernel tick count */
449 Get the RTOS kernel tick frequency.
451 uint32_t osKernelGetTickFreq (void) {
452 /* Return frequency in hertz */
453 return (configTICK_RATE_HZ);
457 Get the RTOS kernel system timer count.
459 uint32_t osKernelGetSysTimerCount (void) {
460 uint32_t irqmask = IS_IRQ_MASKED();
463 #if (configUSE_TICKLESS_IDLE != 0)
466 /* Low Power Tickless Idle controls timer overflow flag and therefore */
467 /* OS_Tick_GetOverflow may be non-functional. As a workaround a reference */
468 /* time is measured here before disabling interrupts. Timer value overflow */
469 /* is then checked by comparing reference against latest time measurement. */
470 /* Timer count value returned by this method is less accurate but if an */
471 /* overflow is missed, an invalid timer count would be returned. */
472 val0 = OS_Tick_GetCount();
479 ticks = xTaskGetTickCount();
480 val = OS_Tick_GetCount();
482 /* Update tick count and timer value when timer overflows */
483 #if (configUSE_TICKLESS_IDLE != 0)
488 if (OS_Tick_GetOverflow() != 0U) {
489 val = OS_Tick_GetCount();
494 val += ticks * OS_Tick_GetInterval();
500 /* Return system timer count */
505 Get the RTOS kernel system timer frequency.
507 uint32_t osKernelGetSysTimerFreq (void) {
508 /* Return frequency in hertz */
509 return (configCPU_CLOCK_HZ);
513 /* ==== Thread Management Functions ==== */
516 Create a thread and add it to Active Threads.
519 - The memory for control block and stack must be provided in the osThreadAttr_t
520 structure in order to allocate object statically.
521 - Attribute osThreadJoinable is not supported, NULL is returned if used.
523 osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr) {
529 #if (configUSE_OS2_CPU_AFFINITY == 1)
530 UBaseType_t core_aff = tskNO_AFFINITY;
535 if ((IRQ_Context() == 0U) && (func != NULL)) {
536 stack = configMINIMAL_STACK_SIZE;
537 prio = (UBaseType_t)osPriorityNormal;
543 if (attr->name != NULL) {
546 if (attr->priority != osPriorityNone) {
547 prio = (UBaseType_t)attr->priority;
550 if ((prio < osPriorityIdle) || (prio > osPriorityISR) || ((attr->attr_bits & osThreadJoinable) == osThreadJoinable)) {
551 /* Invalid priority or unsupported osThreadJoinable attribute used */
555 if (attr->stack_size > 0U) {
556 /* In FreeRTOS stack is not in bytes, but in sizeof(StackType_t) which is 4 on ARM ports. */
557 /* Stack size should be therefore 4 byte aligned in order to avoid division caused side effects */
558 stack = attr->stack_size / sizeof(StackType_t);
561 if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticTask_t)) &&
562 (attr->stack_mem != NULL) && (attr->stack_size > 0U)) {
563 /* The memory for control block and stack is provided, use static object */
567 if ((attr->cb_mem == NULL) && (attr->cb_size == 0U) && (attr->stack_mem == NULL)) {
568 /* Control block and stack memory will be allocated from the dynamic pool */
573 #if (configUSE_OS2_CPU_AFFINITY == 1)
574 if (attr->affinity_mask != 0U) {
575 core_aff = attr->affinity_mask;
584 #if (configSUPPORT_STATIC_ALLOCATION == 1)
585 #if (configUSE_OS2_CPU_AFFINITY == 0)
586 hTask = xTaskCreateStatic ((TaskFunction_t)func,
591 (StackType_t *)attr->stack_mem,
592 (StaticTask_t *)attr->cb_mem);
594 hTask = xTaskCreateStaticAffinitySet ((TaskFunction_t)func,
599 (StackType_t *)attr->stack_mem,
600 (StaticTask_t *)attr->cb_mem,
607 #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
608 #if (configUSE_OS2_CPU_AFFINITY == 0)
609 if (xTaskCreate ((TaskFunction_t )func,
611 (configSTACK_DEPTH_TYPE)stack,
618 if (xTaskCreateAffinitySet ((TaskFunction_t )func,
620 (configSTACK_DEPTH_TYPE)stack,
633 /* Return thread ID */
634 return ((osThreadId_t)hTask);
638 Get name of a thread.
640 const char *osThreadGetName (osThreadId_t thread_id) {
641 TaskHandle_t hTask = (TaskHandle_t)thread_id;
647 else if (IRQ_Context() != 0U) {
648 /* Retrieve the name even though the function is not allowed to be called from ISR */
649 /* Function implementation allows this therefore we make an exception. */
650 name = pcTaskGetName (hTask);
653 name = pcTaskGetName (hTask);
656 /* Return name as null-terminated string */
661 Return the thread ID of the current running thread.
663 osThreadId_t osThreadGetId (void) {
666 id = (osThreadId_t)xTaskGetCurrentTaskHandle();
668 /* Return thread ID */
673 Get current thread state of a thread.
675 osThreadState_t osThreadGetState (osThreadId_t thread_id) {
676 TaskHandle_t hTask = (TaskHandle_t)thread_id;
677 osThreadState_t state;
679 if ((IRQ_Context() != 0U) || (hTask == NULL)) {
680 state = osThreadError;
683 switch (eTaskGetState (hTask)) {
684 case eRunning: state = osThreadRunning; break;
685 case eReady: state = osThreadReady; break;
687 case eSuspended: state = osThreadBlocked; break;
690 default: state = osThreadError; break;
694 /* Return current thread state */
699 Get available stack space of a thread based on stack watermark recording during execution.
701 uint32_t osThreadGetStackSpace (osThreadId_t thread_id) {
702 TaskHandle_t hTask = (TaskHandle_t)thread_id;
705 if ((IRQ_Context() != 0U) || (hTask == NULL)) {
708 sz = (uint32_t)(uxTaskGetStackHighWaterMark(hTask) * sizeof(StackType_t));
711 /* Return remaining stack space in bytes */
716 Change priority of a thread.
718 osStatus_t osThreadSetPriority (osThreadId_t thread_id, osPriority_t priority) {
719 TaskHandle_t hTask = (TaskHandle_t)thread_id;
722 if (IRQ_Context() != 0U) {
725 else if ((hTask == NULL) || (priority < osPriorityIdle) || (priority > osPriorityISR)) {
726 stat = osErrorParameter;
730 vTaskPrioritySet (hTask, (UBaseType_t)priority - 1U);
733 /* Return execution status */
738 Get current priority of a thread.
740 osPriority_t osThreadGetPriority (osThreadId_t thread_id) {
741 TaskHandle_t hTask = (TaskHandle_t)thread_id;
744 if ((IRQ_Context() != 0U) || (hTask == NULL)) {
745 prio = osPriorityError;
747 prio = (osPriority_t)(uxTaskPriorityGet (hTask) + 1U);
750 /* Return current thread priority */
755 Pass control to next thread that is in state READY.
757 osStatus_t osThreadYield (void) {
760 if (IRQ_Context() != 0U) {
767 /* Return execution status */
771 #if (configUSE_OS2_THREAD_SUSPEND_RESUME == 1)
773 Suspend execution of a thread.
775 osStatus_t osThreadSuspend (osThreadId_t thread_id) {
776 TaskHandle_t hTask = (TaskHandle_t)thread_id;
779 if (IRQ_Context() != 0U) {
782 else if (hTask == NULL) {
783 stat = osErrorParameter;
787 vTaskSuspend (hTask);
790 /* Return execution status */
795 Resume execution of a thread.
797 osStatus_t osThreadResume (osThreadId_t thread_id) {
798 TaskHandle_t hTask = (TaskHandle_t)thread_id;
802 if (IRQ_Context() != 0U) {
805 else if (hTask == NULL) {
806 stat = osErrorParameter;
809 tstate = eTaskGetState (hTask);
811 if (tstate == eSuspended) {
812 /* Thread is suspended */
816 /* Not suspended, might be blocked */
817 if (xTaskAbortDelay(hTask) == pdPASS) {
818 /* Thread was unblocked */
821 /* Thread was not blocked */
822 stat = osErrorResource;
827 /* Return execution status */
830 #endif /* (configUSE_OS2_THREAD_SUSPEND_RESUME == 1) */
833 Terminate execution of current running thread.
835 __NO_RETURN void osThreadExit (void) {
836 #ifndef USE_FreeRTOS_HEAP_1
843 Terminate execution of a thread.
845 osStatus_t osThreadTerminate (osThreadId_t thread_id) {
846 TaskHandle_t hTask = (TaskHandle_t)thread_id;
848 #ifndef USE_FreeRTOS_HEAP_1
851 if (IRQ_Context() != 0U) {
854 else if (hTask == NULL) {
855 stat = osErrorParameter;
858 tstate = eTaskGetState (hTask);
860 if (tstate != eDeleted) {
864 stat = osErrorResource;
871 /* Return execution status */
876 Get number of active threads.
878 uint32_t osThreadGetCount (void) {
881 if (IRQ_Context() != 0U) {
884 count = uxTaskGetNumberOfTasks();
887 /* Return number of active threads */
891 #if (configUSE_OS2_THREAD_ENUMERATE == 1)
893 Enumerate active threads.
895 uint32_t osThreadEnumerate (osThreadId_t *thread_array, uint32_t array_items) {
899 if ((IRQ_Context() != 0U) || (thread_array == NULL) || (array_items == 0U)) {
904 /* Allocate memory on heap to temporarily store TaskStatus_t information */
905 count = uxTaskGetNumberOfTasks();
906 task = pvPortMalloc (count * sizeof(TaskStatus_t));
909 /* Retrieve task status information */
910 count = uxTaskGetSystemState (task, count, NULL);
912 /* Copy handles from task status array into provided thread array */
913 for (i = 0U; (i < count) && (i < array_items); i++) {
914 thread_array[i] = (osThreadId_t)task[i].xHandle;
918 (void)xTaskResumeAll();
923 /* Return number of enumerated threads */
926 #endif /* (configUSE_OS2_THREAD_ENUMERATE == 1) */
928 #if (configUSE_OS2_CPU_AFFINITY == 1)
930 Set processor affinity mask of a thread.
932 osStatus_t osThreadSetAffinityMask (osThreadId_t thread_id, uint32_t affinity_mask) {
933 TaskHandle_t hTask = (TaskHandle_t)thread_id;
936 if (IRQ_Context() != 0U) {
939 else if (hTask == NULL) {
940 stat = osErrorParameter;
944 vTaskCoreAffinitySet (hTask, (UBaseType_t)affinity_mask);
947 /* Return execution status */
952 Get current processor affinity mask of a thread.
954 uint32_t osThreadGetAffinityMask (osThreadId_t thread_id) {
955 TaskHandle_t hTask = (TaskHandle_t)thread_id;
956 UBaseType_t affinity_mask;
958 if (IRQ_Context() != 0U) {
961 else if (hTask == NULL) {
965 affinity_mask = vTaskCoreAffinityGet (hTask);
968 /* Return current processor affinity mask */
969 return ((uint32_t)affinity_mask);
971 #endif /* (configUSE_OS2_CPU_AFFINITY == 1) */
973 /* ==== Thread Flags Functions ==== */
975 #if (configUSE_OS2_THREAD_FLAGS == 1)
977 Set the specified Thread Flags of a thread.
979 uint32_t osThreadFlagsSet (osThreadId_t thread_id, uint32_t flags) {
980 TaskHandle_t hTask = (TaskHandle_t)thread_id;
984 if ((hTask == NULL) || ((flags & THREAD_FLAGS_INVALID_BITS) != 0U)) {
985 rflags = (uint32_t)osErrorParameter;
988 rflags = (uint32_t)osError;
990 if (IRQ_Context() != 0U) {
993 (void)xTaskNotifyFromISR (hTask, flags, eSetBits, &yield);
994 (void)xTaskNotifyAndQueryFromISR (hTask, 0, eNoAction, &rflags, NULL);
996 portYIELD_FROM_ISR (yield);
999 (void)xTaskNotify (hTask, flags, eSetBits);
1000 (void)xTaskNotifyAndQuery (hTask, 0, eNoAction, &rflags);
1003 /* Return flags after setting */
1008 Clear the specified Thread Flags of current running thread.
1010 uint32_t osThreadFlagsClear (uint32_t flags) {
1012 uint32_t rflags, cflags;
1014 if (IRQ_Context() != 0U) {
1015 rflags = (uint32_t)osErrorISR;
1017 else if ((flags & THREAD_FLAGS_INVALID_BITS) != 0U) {
1018 rflags = (uint32_t)osErrorParameter;
1021 hTask = xTaskGetCurrentTaskHandle();
1023 if (xTaskNotifyAndQuery (hTask, 0, eNoAction, &cflags) == pdPASS) {
1027 if (xTaskNotify (hTask, cflags, eSetValueWithOverwrite) != pdPASS) {
1028 rflags = (uint32_t)osError;
1032 rflags = (uint32_t)osError;
1036 /* Return flags before clearing */
1041 Get the current Thread Flags of current running thread.
1043 uint32_t osThreadFlagsGet (void) {
1047 if (IRQ_Context() != 0U) {
1048 rflags = (uint32_t)osErrorISR;
1051 hTask = xTaskGetCurrentTaskHandle();
1053 if (xTaskNotifyAndQuery (hTask, 0, eNoAction, &rflags) != pdPASS) {
1054 rflags = (uint32_t)osError;
1058 /* Return current flags */
1063 Wait for one or more Thread Flags of the current running thread to become signaled.
1065 uint32_t osThreadFlagsWait (uint32_t flags, uint32_t options, uint32_t timeout) {
1067 uint32_t rflags, nval;
1069 TickType_t t0, td, tout;
1071 BaseType_t notify = pdFALSE;
1073 if (IRQ_Context() != 0U) {
1074 rflags = (uint32_t)osErrorISR;
1076 else if ((flags & THREAD_FLAGS_INVALID_BITS) != 0U) {
1077 rflags = (uint32_t)osErrorParameter;
1080 if ((options & osFlagsNoClear) == osFlagsNoClear) {
1089 t0 = xTaskGetTickCount();
1091 rval = xTaskNotifyWait (0, clear, &nval, tout);
1093 if (rval == pdPASS) {
1097 if ((rflags & ~flags) != 0) {
1098 /* Other flags already set, notify task to change its state */
1102 if ((options & osFlagsWaitAll) == osFlagsWaitAll) {
1103 if ((flags & rflags) == flags) {
1106 if (timeout == 0U) {
1107 rflags = (uint32_t)osErrorResource;
1113 if ((flags & rflags) != 0) {
1116 if (timeout == 0U) {
1117 rflags = (uint32_t)osErrorResource;
1123 /* Update timeout */
1124 td = xTaskGetTickCount() - t0;
1129 tout = timeout - td;
1134 rflags = (uint32_t)osErrorResource;
1136 rflags = (uint32_t)osErrorTimeout;
1140 while (rval != pdFAIL);
1143 if (notify == pdTRUE) {
1144 hTask = xTaskGetCurrentTaskHandle();
1146 /* Ensure task is already notified without changing existing flags */
1147 if (xTaskNotify(hTask, 0, eNoAction) != pdPASS) {
1148 rflags = (uint32_t)osError;
1152 /* Return flags before clearing */
1155 #endif /* (configUSE_OS2_THREAD_FLAGS == 1) */
1158 /* ==== Generic Wait Functions ==== */
1161 Wait for Timeout (Time Delay).
1163 osStatus_t osDelay (uint32_t ticks) {
1166 if (IRQ_Context() != 0U) {
1177 /* Return execution status */
1182 Wait until specified time.
1184 osStatus_t osDelayUntil (uint32_t ticks) {
1185 TickType_t tcnt, delay;
1188 if (IRQ_Context() != 0U) {
1193 tcnt = xTaskGetTickCount();
1195 /* Determine remaining number of ticks to delay */
1196 delay = (TickType_t)ticks - tcnt;
1198 /* Check if target tick has not expired */
1199 if((delay != 0U) && (0 == (delay >> (8 * sizeof(TickType_t) - 1)))) {
1200 if (xTaskDelayUntil (&tcnt, delay) == pdFALSE) {
1207 /* No delay or already expired */
1208 stat = osErrorParameter;
1212 /* Return execution status */
1217 /* ==== Timer Management Functions ==== */
1219 #if (configUSE_OS2_TIMER == 1)
1221 static void TimerCallback (TimerHandle_t hTimer) {
1222 TimerCallback_t *callb;
1224 /* Retrieve pointer to callback function and argument */
1225 callb = (TimerCallback_t *)pvTimerGetTimerID (hTimer);
1227 /* Remove dynamic allocation flag */
1228 callb = (TimerCallback_t *)((uint32_t)callb & ~1U);
1230 if (callb != NULL) {
1231 callb->func (callb->arg);
1236 Create and Initialize a timer.
1238 osTimerId_t osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr) {
1240 TimerHandle_t hTimer;
1241 TimerCallback_t *callb;
1248 if ((IRQ_Context() == 0U) && (func != NULL)) {
1252 #if (configSUPPORT_STATIC_ALLOCATION == 1)
1253 /* Static memory allocation is available: check if memory for control block */
1254 /* is provided and if it also contains space for callback and its argument */
1255 if ((attr != NULL) && (attr->cb_mem != NULL)) {
1256 if (attr->cb_size >= (sizeof(StaticTimer_t) + sizeof(TimerCallback_t))) {
1257 callb = (TimerCallback_t *)((uint32_t)attr->cb_mem + sizeof(StaticTimer_t));
1262 #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
1263 /* Dynamic memory allocation is available: if memory for callback and */
1264 /* its argument is not provided, allocate it from dynamic memory pool */
1265 if (callb == NULL) {
1266 callb = (TimerCallback_t *)pvPortMalloc (sizeof(TimerCallback_t));
1268 if (callb != NULL) {
1269 /* Callback memory was allocated from dynamic pool, set flag */
1275 if (callb != NULL) {
1277 callb->arg = argument;
1279 if (type == osTimerOnce) {
1289 if (attr->name != NULL) {
1293 if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticTimer_t))) {
1294 /* The memory for control block is provided, use static object */
1298 if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
1299 /* Control block will be allocated from the dynamic pool */
1307 /* Store callback memory dynamic allocation flag */
1308 callb = (TimerCallback_t *)((uint32_t)callb | callb_dyn);
1310 TimerCallback function is always provided as a callback and is used to call application
1311 specified function with its argument both stored in structure callb.
1314 #if (configSUPPORT_STATIC_ALLOCATION == 1)
1315 hTimer = xTimerCreateStatic (name, 1, reload, callb, TimerCallback, (StaticTimer_t *)attr->cb_mem);
1320 #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
1321 hTimer = xTimerCreate (name, 1, reload, callb, TimerCallback);
1326 #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
1327 if ((hTimer == NULL) && (callb != NULL) && (callb_dyn == 1U)) {
1328 /* Failed to create a timer, release allocated resources */
1329 callb = (TimerCallback_t *)((uint32_t)callb & ~1U);
1337 /* Return timer ID */
1338 return ((osTimerId_t)hTimer);
1342 Get name of a timer.
1344 const char *osTimerGetName (osTimerId_t timer_id) {
1345 TimerHandle_t hTimer = (TimerHandle_t)timer_id;
1348 if (hTimer == NULL) {
1351 else if (IRQ_Context() != 0U) {
1352 /* Retrieve the name even though the function is not allowed to be called from ISR */
1353 /* Function implementation allows this therefore we make an exception. */
1354 p = pcTimerGetName (hTimer);
1357 p = pcTimerGetName (hTimer);
1360 /* Return name as null-terminated string */
1365 Start or restart a timer.
1367 osStatus_t osTimerStart (osTimerId_t timer_id, uint32_t ticks) {
1368 TimerHandle_t hTimer = (TimerHandle_t)timer_id;
1371 if (IRQ_Context() != 0U) {
1374 else if ((hTimer == NULL) || (ticks == 0U)) {
1375 stat = osErrorParameter;
1378 if (xTimerChangePeriod (hTimer, ticks, 0) == pdPASS) {
1381 stat = osErrorResource;
1385 /* Return execution status */
1392 osStatus_t osTimerStop (osTimerId_t timer_id) {
1393 TimerHandle_t hTimer = (TimerHandle_t)timer_id;
1396 if (IRQ_Context() != 0U) {
1399 else if (hTimer == NULL) {
1400 stat = osErrorParameter;
1403 if (xTimerIsTimerActive (hTimer) == pdFALSE) {
1404 stat = osErrorResource;
1407 if (xTimerStop (hTimer, 0) == pdPASS) {
1415 /* Return execution status */
1420 Check if a timer is running.
1422 uint32_t osTimerIsRunning (osTimerId_t timer_id) {
1423 TimerHandle_t hTimer = (TimerHandle_t)timer_id;
1426 if ((IRQ_Context() != 0U) || (hTimer == NULL)) {
1429 running = (uint32_t)xTimerIsTimerActive (hTimer);
1432 /* Return 0: not running, 1: running */
1439 osStatus_t osTimerDelete (osTimerId_t timer_id) {
1440 TimerHandle_t hTimer = (TimerHandle_t)timer_id;
1442 #ifndef USE_FreeRTOS_HEAP_1
1443 #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
1444 TimerCallback_t *callb;
1447 if (IRQ_Context() != 0U) {
1450 else if (hTimer == NULL) {
1451 stat = osErrorParameter;
1454 #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
1455 callb = (TimerCallback_t *)pvTimerGetTimerID (hTimer);
1458 if (xTimerDelete (hTimer, 0) == pdPASS) {
1459 #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
1460 if ((uint32_t)callb & 1U) {
1461 /* Callback memory was allocated from dynamic pool, clear flag */
1462 callb = (TimerCallback_t *)((uint32_t)callb & ~1U);
1464 /* Return allocated memory to dynamic pool */
1470 stat = osErrorResource;
1477 /* Return execution status */
1480 #endif /* (configUSE_OS2_TIMER == 1) */
1483 /* ==== Event Flags Management Functions ==== */
1486 Create and Initialize an Event Flags object.
1489 - Event flags are limited to 24 bits.
1491 osEventFlagsId_t osEventFlagsNew (const osEventFlagsAttr_t *attr) {
1492 EventGroupHandle_t hEventGroup;
1497 if (IRQ_Context() == 0U) {
1501 if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticEventGroup_t))) {
1502 /* The memory for control block is provided, use static object */
1506 if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
1507 /* Control block will be allocated from the dynamic pool */
1517 #if (configSUPPORT_STATIC_ALLOCATION == 1)
1518 hEventGroup = xEventGroupCreateStatic (attr->cb_mem);
1523 #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
1524 hEventGroup = xEventGroupCreate();
1530 /* Return event flags ID */
1531 return ((osEventFlagsId_t)hEventGroup);
1535 Set the specified Event Flags.
1538 - Event flags are limited to 24 bits.
1540 uint32_t osEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags) {
1541 EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
1545 if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) {
1546 rflags = (uint32_t)osErrorParameter;
1548 else if (IRQ_Context() != 0U) {
1549 #if (configUSE_OS2_EVENTFLAGS_FROM_ISR == 0)
1551 /* Enable timers and xTimerPendFunctionCall function to support osEventFlagsSet from ISR */
1552 rflags = (uint32_t)osErrorResource;
1556 if (xEventGroupSetBitsFromISR (hEventGroup, (EventBits_t)flags, &yield) == pdFAIL) {
1557 rflags = (uint32_t)osErrorResource;
1559 /* Retrieve bits that are already set and add flags to be set in current call */
1560 rflags = xEventGroupGetBitsFromISR (hEventGroup);
1562 portYIELD_FROM_ISR (yield);
1567 rflags = xEventGroupSetBits (hEventGroup, (EventBits_t)flags);
1570 /* Return event flags after setting */
1575 Clear the specified Event Flags.
1578 - Event flags are limited to 24 bits.
1580 uint32_t osEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags) {
1581 EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
1584 if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) {
1585 rflags = (uint32_t)osErrorParameter;
1587 else if (IRQ_Context() != 0U) {
1588 #if (configUSE_OS2_EVENTFLAGS_FROM_ISR == 0)
1589 /* Enable timers and xTimerPendFunctionCall function to support osEventFlagsSet from ISR */
1590 rflags = (uint32_t)osErrorResource;
1592 rflags = xEventGroupGetBitsFromISR (hEventGroup);
1594 if (xEventGroupClearBitsFromISR (hEventGroup, (EventBits_t)flags) == pdFAIL) {
1595 rflags = (uint32_t)osErrorResource;
1598 /* xEventGroupClearBitsFromISR only registers clear operation in the timer command queue. */
1599 /* Yield is required here otherwise clear operation might not execute in the right order. */
1600 /* See https://github.com/FreeRTOS/FreeRTOS-Kernel/issues/93 for more info. */
1601 portYIELD_FROM_ISR (pdTRUE);
1606 rflags = xEventGroupClearBits (hEventGroup, (EventBits_t)flags);
1609 /* Return event flags before clearing */
1614 Get the current Event Flags.
1617 - Event flags are limited to 24 bits.
1619 uint32_t osEventFlagsGet (osEventFlagsId_t ef_id) {
1620 EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
1623 if (ef_id == NULL) {
1626 else if (IRQ_Context() != 0U) {
1627 rflags = xEventGroupGetBitsFromISR (hEventGroup);
1630 rflags = xEventGroupGetBits (hEventGroup);
1633 /* Return current event flags */
1638 Wait for one or more Event Flags to become signaled.
1641 - Event flags are limited to 24 bits.
1642 - osEventFlagsWait cannot be called from an ISR.
1644 uint32_t osEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout) {
1645 EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
1646 BaseType_t wait_all;
1647 BaseType_t exit_clr;
1650 if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) {
1651 rflags = (uint32_t)osErrorParameter;
1653 else if (IRQ_Context() != 0U) {
1654 if (timeout == 0U) {
1655 /* Try semantic is not supported */
1656 rflags = (uint32_t)osErrorISR;
1658 /* Calling osEventFlagsWait from ISR with non-zero timeout is invalid */
1659 rflags = (uint32_t)osFlagsErrorParameter;
1663 if (options & osFlagsWaitAll) {
1669 if (options & osFlagsNoClear) {
1675 rflags = xEventGroupWaitBits (hEventGroup, (EventBits_t)flags, exit_clr, wait_all, (TickType_t)timeout);
1677 if (options & osFlagsWaitAll) {
1678 if ((flags & rflags) != flags) {
1680 rflags = (uint32_t)osErrorTimeout;
1682 rflags = (uint32_t)osErrorResource;
1687 if ((flags & rflags) == 0U) {
1689 rflags = (uint32_t)osErrorTimeout;
1691 rflags = (uint32_t)osErrorResource;
1697 /* Return event flags before clearing */
1702 Delete an Event Flags object.
1704 osStatus_t osEventFlagsDelete (osEventFlagsId_t ef_id) {
1705 EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
1708 #ifndef USE_FreeRTOS_HEAP_1
1709 if (IRQ_Context() != 0U) {
1712 else if (hEventGroup == NULL) {
1713 stat = osErrorParameter;
1717 vEventGroupDelete (hEventGroup);
1723 /* Return execution status */
1728 /* ==== Mutex Management Functions ==== */
1730 #if (configUSE_OS2_MUTEX == 1)
1732 Create and Initialize a Mutex object.
1735 - Priority inherit protocol is used by default, osMutexPrioInherit attribute is ignored.
1736 - Robust mutex is not supported, NULL is returned if used.
1738 osMutexId_t osMutexNew (const osMutexAttr_t *attr) {
1739 SemaphoreHandle_t hMutex;
1746 if (IRQ_Context() == 0U) {
1748 type = attr->attr_bits;
1753 if ((type & osMutexRecursive) == osMutexRecursive) {
1759 if ((type & osMutexRobust) != osMutexRobust) {
1763 if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) {
1764 /* The memory for control block is provided, use static object */
1768 if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
1769 /* Control block will be allocated from the dynamic pool */
1779 #if (configSUPPORT_STATIC_ALLOCATION == 1)
1781 #if (configUSE_RECURSIVE_MUTEXES == 1)
1782 hMutex = xSemaphoreCreateRecursiveMutexStatic (attr->cb_mem);
1786 hMutex = xSemaphoreCreateMutexStatic (attr->cb_mem);
1792 #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
1794 #if (configUSE_RECURSIVE_MUTEXES == 1)
1795 hMutex = xSemaphoreCreateRecursiveMutex ();
1798 hMutex = xSemaphoreCreateMutex ();
1804 #if (configQUEUE_REGISTRY_SIZE > 0)
1805 if (hMutex != NULL) {
1806 if ((attr != NULL) && (attr->name != NULL)) {
1807 /* Only non-NULL name objects are added to the Queue Registry */
1808 vQueueAddToRegistry (hMutex, attr->name);
1813 if ((hMutex != NULL) && (rmtx != 0U)) {
1814 /* Set LSB as 'recursive mutex flag' */
1815 hMutex = (SemaphoreHandle_t)((uint32_t)hMutex | 1U);
1820 /* Return mutex ID */
1821 return ((osMutexId_t)hMutex);
1825 Acquire a Mutex or timeout if it is locked.
1827 osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) {
1828 SemaphoreHandle_t hMutex;
1832 hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
1834 /* Extract recursive mutex flag */
1835 rmtx = (uint32_t)mutex_id & 1U;
1839 if (IRQ_Context() != 0U) {
1842 else if (hMutex == NULL) {
1843 stat = osErrorParameter;
1847 #if (configUSE_RECURSIVE_MUTEXES == 1)
1848 if (xSemaphoreTakeRecursive (hMutex, timeout) != pdPASS) {
1849 if (timeout != 0U) {
1850 stat = osErrorTimeout;
1852 stat = osErrorResource;
1858 if (xSemaphoreTake (hMutex, timeout) != pdPASS) {
1859 if (timeout != 0U) {
1860 stat = osErrorTimeout;
1862 stat = osErrorResource;
1868 /* Return execution status */
1873 Release a Mutex that was acquired by osMutexAcquire.
1875 osStatus_t osMutexRelease (osMutexId_t mutex_id) {
1876 SemaphoreHandle_t hMutex;
1880 hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
1882 /* Extract recursive mutex flag */
1883 rmtx = (uint32_t)mutex_id & 1U;
1887 if (IRQ_Context() != 0U) {
1890 else if (hMutex == NULL) {
1891 stat = osErrorParameter;
1895 #if (configUSE_RECURSIVE_MUTEXES == 1)
1896 if (xSemaphoreGiveRecursive (hMutex) != pdPASS) {
1897 stat = osErrorResource;
1902 if (xSemaphoreGive (hMutex) != pdPASS) {
1903 stat = osErrorResource;
1908 /* Return execution status */
1913 Get Thread which owns a Mutex object.
1915 osThreadId_t osMutexGetOwner (osMutexId_t mutex_id) {
1916 SemaphoreHandle_t hMutex;
1919 hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
1921 if ((IRQ_Context() != 0U) || (hMutex == NULL)) {
1924 owner = (osThreadId_t)xSemaphoreGetMutexHolder (hMutex);
1927 /* Return owner thread ID */
1932 Delete a Mutex object.
1934 osStatus_t osMutexDelete (osMutexId_t mutex_id) {
1936 #ifndef USE_FreeRTOS_HEAP_1
1937 SemaphoreHandle_t hMutex;
1939 hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
1941 if (IRQ_Context() != 0U) {
1944 else if (hMutex == NULL) {
1945 stat = osErrorParameter;
1948 #if (configQUEUE_REGISTRY_SIZE > 0)
1949 vQueueUnregisterQueue (hMutex);
1952 vSemaphoreDelete (hMutex);
1958 /* Return execution status */
1961 #endif /* (configUSE_OS2_MUTEX == 1) */
1964 /* ==== Semaphore Management Functions ==== */
1967 Create and Initialize a Semaphore object.
1969 osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) {
1970 SemaphoreHandle_t hSemaphore;
1975 if ((IRQ_Context() == 0U) && (max_count > 0U) && (initial_count <= max_count)) {
1979 if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) {
1980 /* The memory for control block is provided, use static object */
1984 if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
1985 /* Control block will be allocated from the dynamic pool */
1995 if (max_count == 1U) {
1997 #if (configSUPPORT_STATIC_ALLOCATION == 1)
1998 hSemaphore = xSemaphoreCreateBinaryStatic ((StaticSemaphore_t *)attr->cb_mem);
2002 #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
2003 hSemaphore = xSemaphoreCreateBinary();
2007 if ((hSemaphore != NULL) && (initial_count != 0U)) {
2008 if (xSemaphoreGive (hSemaphore) != pdPASS) {
2009 vSemaphoreDelete (hSemaphore);
2016 #if (configSUPPORT_STATIC_ALLOCATION == 1)
2017 hSemaphore = xSemaphoreCreateCountingStatic (max_count, initial_count, (StaticSemaphore_t *)attr->cb_mem);
2021 #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
2022 hSemaphore = xSemaphoreCreateCounting (max_count, initial_count);
2027 #if (configQUEUE_REGISTRY_SIZE > 0)
2028 if (hSemaphore != NULL) {
2029 if ((attr != NULL) && (attr->name != NULL)) {
2030 /* Only non-NULL name objects are added to the Queue Registry */
2031 vQueueAddToRegistry (hSemaphore, attr->name);
2038 /* Return semaphore ID */
2039 return ((osSemaphoreId_t)hSemaphore);
2043 Acquire a Semaphore token or timeout if no tokens are available.
2045 osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) {
2046 SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
2052 if (hSemaphore == NULL) {
2053 stat = osErrorParameter;
2055 else if (IRQ_Context() != 0U) {
2056 if (timeout != 0U) {
2057 stat = osErrorParameter;
2062 if (xSemaphoreTakeFromISR (hSemaphore, &yield) != pdPASS) {
2063 stat = osErrorResource;
2065 portYIELD_FROM_ISR (yield);
2070 if (xSemaphoreTake (hSemaphore, (TickType_t)timeout) != pdPASS) {
2071 if (timeout != 0U) {
2072 stat = osErrorTimeout;
2074 stat = osErrorResource;
2079 /* Return execution status */
2084 Release a Semaphore token up to the initial maximum count.
2086 osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id) {
2087 SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
2093 if (hSemaphore == NULL) {
2094 stat = osErrorParameter;
2096 else if (IRQ_Context() != 0U) {
2099 if (xSemaphoreGiveFromISR (hSemaphore, &yield) != pdTRUE) {
2100 stat = osErrorResource;
2102 portYIELD_FROM_ISR (yield);
2106 if (xSemaphoreGive (hSemaphore) != pdPASS) {
2107 stat = osErrorResource;
2111 /* Return execution status */
2116 Get current Semaphore token count.
2118 uint32_t osSemaphoreGetCount (osSemaphoreId_t semaphore_id) {
2119 SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
2122 if (hSemaphore == NULL) {
2125 else if (IRQ_Context() != 0U) {
2126 count = (uint32_t)uxSemaphoreGetCountFromISR (hSemaphore);
2128 count = (uint32_t)uxSemaphoreGetCount (hSemaphore);
2131 /* Return number of tokens */
2136 Delete a Semaphore object.
2138 osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id) {
2139 SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
2142 #ifndef USE_FreeRTOS_HEAP_1
2143 if (IRQ_Context() != 0U) {
2146 else if (hSemaphore == NULL) {
2147 stat = osErrorParameter;
2150 #if (configQUEUE_REGISTRY_SIZE > 0)
2151 vQueueUnregisterQueue (hSemaphore);
2155 vSemaphoreDelete (hSemaphore);
2161 /* Return execution status */
2166 /* ==== Message Queue Management Functions ==== */
2169 Create and Initialize a Message Queue object.
2172 - The memory for control block and and message data must be provided in the
2173 osThreadAttr_t structure in order to allocate object statically.
2175 osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr) {
2176 QueueHandle_t hQueue;
2181 if ((IRQ_Context() == 0U) && (msg_count > 0U) && (msg_size > 0U)) {
2185 if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticQueue_t)) &&
2186 (attr->mq_mem != NULL) && (attr->mq_size >= (msg_count * msg_size))) {
2187 /* The memory for control block and message data is provided, use static object */
2191 if ((attr->cb_mem == NULL) && (attr->cb_size == 0U) &&
2192 (attr->mq_mem == NULL) && (attr->mq_size == 0U)) {
2193 /* Control block will be allocated from the dynamic pool */
2203 #if (configSUPPORT_STATIC_ALLOCATION == 1)
2204 hQueue = xQueueCreateStatic (msg_count, msg_size, attr->mq_mem, attr->cb_mem);
2209 #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
2210 hQueue = xQueueCreate (msg_count, msg_size);
2215 #if (configQUEUE_REGISTRY_SIZE > 0)
2216 if (hQueue != NULL) {
2217 if ((attr != NULL) && (attr->name != NULL)) {
2218 /* Only non-NULL name objects are added to the Queue Registry */
2219 vQueueAddToRegistry (hQueue, attr->name);
2226 /* Return message queue ID */
2227 return ((osMessageQueueId_t)hQueue);
2231 Put a Message into a Queue or timeout if Queue is full.
2234 - Message priority is ignored
2236 osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) {
2237 QueueHandle_t hQueue = (QueueHandle_t)mq_id;
2241 (void)msg_prio; /* Message priority is ignored */
2245 if (IRQ_Context() != 0U) {
2246 if ((hQueue == NULL) || (msg_ptr == NULL) || (timeout != 0U)) {
2247 stat = osErrorParameter;
2252 if (xQueueSendToBackFromISR (hQueue, msg_ptr, &yield) != pdTRUE) {
2253 stat = osErrorResource;
2255 portYIELD_FROM_ISR (yield);
2260 if ((hQueue == NULL) || (msg_ptr == NULL)) {
2261 stat = osErrorParameter;
2264 if (xQueueSendToBack (hQueue, msg_ptr, (TickType_t)timeout) != pdPASS) {
2265 if (timeout != 0U) {
2266 stat = osErrorTimeout;
2268 stat = osErrorResource;
2274 /* Return execution status */
2279 Get a Message from a Queue or timeout if Queue is empty.
2282 - Message priority is ignored
2284 osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
2285 QueueHandle_t hQueue = (QueueHandle_t)mq_id;
2289 (void)msg_prio; /* Message priority is ignored */
2293 if (IRQ_Context() != 0U) {
2294 if ((hQueue == NULL) || (msg_ptr == NULL) || (timeout != 0U)) {
2295 stat = osErrorParameter;
2300 if (xQueueReceiveFromISR (hQueue, msg_ptr, &yield) != pdPASS) {
2301 stat = osErrorResource;
2303 portYIELD_FROM_ISR (yield);
2308 if ((hQueue == NULL) || (msg_ptr == NULL)) {
2309 stat = osErrorParameter;
2312 if (xQueueReceive (hQueue, msg_ptr, (TickType_t)timeout) != pdPASS) {
2313 if (timeout != 0U) {
2314 stat = osErrorTimeout;
2316 stat = osErrorResource;
2322 /* Return execution status */
2327 Get maximum number of messages in a Message Queue.
2329 uint32_t osMessageQueueGetCapacity (osMessageQueueId_t mq_id) {
2330 QueueHandle_t hQueue = (QueueHandle_t)mq_id;
2333 if (hQueue == NULL) {
2336 capacity = uxQueueGetQueueLength (hQueue);
2339 /* Return maximum number of messages */
2344 Get maximum message size in a Message Queue.
2346 uint32_t osMessageQueueGetMsgSize (osMessageQueueId_t mq_id) {
2347 QueueHandle_t hQueue = (QueueHandle_t)mq_id;
2350 if (hQueue == NULL) {
2353 size = uxQueueGetQueueItemSize (hQueue);
2356 /* Return maximum message size */
2361 Get number of queued messages in a Message Queue.
2363 uint32_t osMessageQueueGetCount (osMessageQueueId_t mq_id) {
2364 QueueHandle_t hQueue = (QueueHandle_t)mq_id;
2367 if (hQueue == NULL) {
2370 else if (IRQ_Context() != 0U) {
2371 count = uxQueueMessagesWaitingFromISR (hQueue);
2374 count = uxQueueMessagesWaiting (hQueue);
2377 /* Return number of queued messages */
2378 return ((uint32_t)count);
2382 Get number of available slots for messages in a Message Queue.
2384 uint32_t osMessageQueueGetSpace (osMessageQueueId_t mq_id) {
2385 QueueHandle_t hQueue = (QueueHandle_t)mq_id;
2389 if (hQueue == NULL) {
2392 else if (IRQ_Context() != 0U) {
2393 isrm = taskENTER_CRITICAL_FROM_ISR();
2395 space = uxQueueGetQueueLength (hQueue) - uxQueueMessagesWaiting (hQueue);
2397 taskEXIT_CRITICAL_FROM_ISR(isrm);
2400 space = (uint32_t)uxQueueSpacesAvailable (hQueue);
2403 /* Return number of available slots */
2408 Reset a Message Queue to initial empty state.
2410 osStatus_t osMessageQueueReset (osMessageQueueId_t mq_id) {
2411 QueueHandle_t hQueue = (QueueHandle_t)mq_id;
2414 if (IRQ_Context() != 0U) {
2417 else if (hQueue == NULL) {
2418 stat = osErrorParameter;
2422 (void)xQueueReset (hQueue);
2425 /* Return execution status */
2430 Delete a Message Queue object.
2432 osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id) {
2433 QueueHandle_t hQueue = (QueueHandle_t)mq_id;
2436 #ifndef USE_FreeRTOS_HEAP_1
2437 if (IRQ_Context() != 0U) {
2440 else if (hQueue == NULL) {
2441 stat = osErrorParameter;
2444 #if (configQUEUE_REGISTRY_SIZE > 0)
2445 vQueueUnregisterQueue (hQueue);
2449 vQueueDelete (hQueue);
2455 /* Return execution status */
2460 /* ==== Memory Pool Management Functions ==== */
2462 #ifdef FREERTOS_MPOOL_H_
2463 /* Static memory pool functions */
2464 static void FreeBlock (MemPool_t *mp, void *block);
2465 static void *AllocBlock (MemPool_t *mp);
2466 static void *CreateBlock (MemPool_t *mp);
2469 Create and Initialize a Memory Pool object.
2471 osMemoryPoolId_t osMemoryPoolNew (uint32_t block_count, uint32_t block_size, const osMemoryPoolAttr_t *attr) {
2474 int32_t mem_cb, mem_mp;
2477 if (IRQ_Context() != 0U) {
2480 else if ((block_count == 0U) || (block_size == 0U)) {
2485 sz = MEMPOOL_ARR_SIZE (block_count, block_size);
2492 if (attr->name != NULL) {
2496 if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(MemPool_t))) {
2497 /* Static control block is provided */
2500 else if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
2501 /* Allocate control block memory on heap */
2505 if ((attr->mp_mem == NULL) && (attr->mp_size == 0U)) {
2506 /* Allocate memory array on heap */
2510 if (attr->mp_mem != NULL) {
2511 /* Check if array is 4-byte aligned */
2512 if (((uint32_t)attr->mp_mem & 3U) == 0U) {
2513 /* Check if array big enough */
2514 if (attr->mp_size >= sz) {
2515 /* Static memory pool array is provided */
2523 /* Attributes not provided, allocate memory on heap */
2529 mp = pvPortMalloc (sizeof(MemPool_t));
2535 /* Create a semaphore (max count == initial count == block_count) */
2536 #if (configSUPPORT_STATIC_ALLOCATION == 1)
2537 mp->sem = xSemaphoreCreateCountingStatic (block_count, block_count, &mp->mem_sem);
2538 #elif (configSUPPORT_DYNAMIC_ALLOCATION == 1)
2539 mp->sem = xSemaphoreCreateCounting (block_count, block_count);
2544 if (mp->sem != NULL) {
2545 /* Setup memory array */
2547 mp->mem_arr = pvPortMalloc (sz);
2549 mp->mem_arr = attr->mp_mem;
2554 if ((mp != NULL) && (mp->mem_arr != NULL)) {
2555 /* Memory pool can be created */
2559 mp->bl_sz = block_size;
2560 mp->bl_cnt = block_count;
2563 /* Set heap allocated memory flags */
2564 mp->status = MPOOL_STATUS;
2567 /* Control block on heap */
2571 /* Memory array on heap */
2576 /* Memory pool cannot be created, release allocated resources */
2577 if ((mem_cb == 0) && (mp != NULL)) {
2578 /* Free control block memory */
2585 /* Return memory pool ID */
2590 Get name of a Memory Pool object.
2592 const char *osMemoryPoolGetName (osMemoryPoolId_t mp_id) {
2593 MemPool_t *mp = (osMemoryPoolId_t)mp_id;
2596 if (mp_id == NULL) {
2599 else if (IRQ_Context() != 0U) {
2606 /* Return name as null-terminated string */
2611 Allocate a memory block from a Memory Pool.
2613 void *osMemoryPoolAlloc (osMemoryPoolId_t mp_id, uint32_t timeout) {
2618 if (mp_id == NULL) {
2619 /* Invalid input parameters */
2625 mp = (MemPool_t *)mp_id;
2627 if ((mp->status & MPOOL_STATUS) == MPOOL_STATUS) {
2628 if (IRQ_Context() != 0U) {
2629 if (timeout == 0U) {
2630 if (xSemaphoreTakeFromISR (mp->sem, NULL) == pdTRUE) {
2631 if ((mp->status & MPOOL_STATUS) == MPOOL_STATUS) {
2632 isrm = taskENTER_CRITICAL_FROM_ISR();
2634 /* Get a block from the free-list */
2635 block = AllocBlock(mp);
2637 if (block == NULL) {
2638 /* List of free blocks is empty, 'create' new block */
2639 block = CreateBlock(mp);
2642 taskEXIT_CRITICAL_FROM_ISR(isrm);
2648 if (xSemaphoreTake (mp->sem, (TickType_t)timeout) == pdTRUE) {
2649 if ((mp->status & MPOOL_STATUS) == MPOOL_STATUS) {
2650 taskENTER_CRITICAL();
2652 /* Get a block from the free-list */
2653 block = AllocBlock(mp);
2655 if (block == NULL) {
2656 /* List of free blocks is empty, 'create' new block */
2657 block = CreateBlock(mp);
2660 taskEXIT_CRITICAL();
2667 /* Return memory block address */
2672 Return an allocated memory block back to a Memory Pool.
2674 osStatus_t osMemoryPoolFree (osMemoryPoolId_t mp_id, void *block) {
2680 if ((mp_id == NULL) || (block == NULL)) {
2681 /* Invalid input parameters */
2682 stat = osErrorParameter;
2685 mp = (MemPool_t *)mp_id;
2687 if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) {
2688 /* Invalid object status */
2689 stat = osErrorResource;
2691 else if ((block < (void *)&mp->mem_arr[0]) || (block > (void*)&mp->mem_arr[mp->mem_sz-1])) {
2692 /* Block pointer outside of memory array area */
2693 stat = osErrorParameter;
2698 if (IRQ_Context() != 0U) {
2699 if (uxSemaphoreGetCountFromISR (mp->sem) == mp->bl_cnt) {
2700 stat = osErrorResource;
2703 isrm = taskENTER_CRITICAL_FROM_ISR();
2705 /* Add block to the list of free blocks */
2706 FreeBlock(mp, block);
2708 taskEXIT_CRITICAL_FROM_ISR(isrm);
2711 xSemaphoreGiveFromISR (mp->sem, &yield);
2712 portYIELD_FROM_ISR (yield);
2716 if (uxSemaphoreGetCount (mp->sem) == mp->bl_cnt) {
2717 stat = osErrorResource;
2720 taskENTER_CRITICAL();
2722 /* Add block to the list of free blocks */
2723 FreeBlock(mp, block);
2725 taskEXIT_CRITICAL();
2727 xSemaphoreGive (mp->sem);
2733 /* Return execution status */
2738 Get maximum number of memory blocks in a Memory Pool.
2740 uint32_t osMemoryPoolGetCapacity (osMemoryPoolId_t mp_id) {
2744 if (mp_id == NULL) {
2745 /* Invalid input parameters */
2749 mp = (MemPool_t *)mp_id;
2751 if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) {
2752 /* Invalid object status */
2760 /* Return maximum number of memory blocks */
2765 Get memory block size in a Memory Pool.
2767 uint32_t osMemoryPoolGetBlockSize (osMemoryPoolId_t mp_id) {
2771 if (mp_id == NULL) {
2772 /* Invalid input parameters */
2776 mp = (MemPool_t *)mp_id;
2778 if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) {
2779 /* Invalid object status */
2787 /* Return memory block size in bytes */
2792 Get number of memory blocks used in a Memory Pool.
2794 uint32_t osMemoryPoolGetCount (osMemoryPoolId_t mp_id) {
2798 if (mp_id == NULL) {
2799 /* Invalid input parameters */
2803 mp = (MemPool_t *)mp_id;
2805 if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) {
2806 /* Invalid object status */
2810 if (IRQ_Context() != 0U) {
2811 n = uxSemaphoreGetCountFromISR (mp->sem);
2813 n = uxSemaphoreGetCount (mp->sem);
2820 /* Return number of memory blocks used */
2825 Get number of memory blocks available in a Memory Pool.
2827 uint32_t osMemoryPoolGetSpace (osMemoryPoolId_t mp_id) {
2831 if (mp_id == NULL) {
2832 /* Invalid input parameters */
2836 mp = (MemPool_t *)mp_id;
2838 if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) {
2839 /* Invalid object status */
2843 if (IRQ_Context() != 0U) {
2844 n = uxSemaphoreGetCountFromISR (mp->sem);
2846 n = uxSemaphoreGetCount (mp->sem);
2851 /* Return number of memory blocks available */
2856 Delete a Memory Pool object.
2858 osStatus_t osMemoryPoolDelete (osMemoryPoolId_t mp_id) {
2862 if (mp_id == NULL) {
2863 /* Invalid input parameters */
2864 stat = osErrorParameter;
2866 else if (IRQ_Context() != 0U) {
2870 mp = (MemPool_t *)mp_id;
2872 taskENTER_CRITICAL();
2874 /* Invalidate control block status */
2875 mp->status = mp->status & 3U;
2877 /* Wake-up tasks waiting for pool semaphore */
2878 while (xSemaphoreGive (mp->sem) == pdTRUE);
2884 if ((mp->status & 2U) != 0U) {
2885 /* Memory pool array allocated on heap */
2886 vPortFree (mp->mem_arr);
2888 if ((mp->status & 1U) != 0U) {
2889 /* Memory pool control block allocated on heap */
2893 taskEXIT_CRITICAL();
2898 /* Return execution status */
2903 Create new block given according to the current block index.
2905 static void *CreateBlock (MemPool_t *mp) {
2906 MemPoolBlock_t *p = NULL;
2908 if (mp->n < mp->bl_cnt) {
2909 /* Unallocated blocks exist, set pointer to new block */
2910 p = (void *)(mp->mem_arr + (mp->bl_sz * mp->n));
2912 /* Increment block index */
2920 Allocate a block by reading the list of free blocks.
2922 static void *AllocBlock (MemPool_t *mp) {
2923 MemPoolBlock_t *p = NULL;
2925 if (mp->head != NULL) {
2926 /* List of free block exists, get head block */
2929 /* Head block is now next on the list */
2937 Free block by putting it to the list of free blocks.
2939 static void FreeBlock (MemPool_t *mp, void *block) {
2940 MemPoolBlock_t *p = block;
2942 /* Store current head into block memory space */
2945 /* Store current block as new head */
2948 #endif /* FREERTOS_MPOOL_H_ */
2949 /*---------------------------------------------------------------------------*/
2951 /* Callback function prototypes */
2952 extern void vApplicationIdleHook (void);
2953 extern void vApplicationMallocFailedHook (void);
2954 extern void vApplicationDaemonTaskStartupHook (void);
2957 Dummy implementation of the callback function vApplicationIdleHook().
2959 #if (configUSE_IDLE_HOOK == 1)
2960 __WEAK void vApplicationIdleHook (void){}
2964 Dummy implementation of the callback function vApplicationTickHook().
2966 #if (configUSE_TICK_HOOK == 1)
2967 __WEAK void vApplicationTickHook (void){}
2971 Dummy implementation of the callback function vApplicationMallocFailedHook().
2973 #if (configUSE_MALLOC_FAILED_HOOK == 1)
2974 __WEAK void vApplicationMallocFailedHook (void) {
2975 /* Assert when malloc failed hook is enabled but no application defined function exists */
2981 Dummy implementation of the callback function vApplicationDaemonTaskStartupHook().
2983 #if (configUSE_DAEMON_TASK_STARTUP_HOOK == 1)
2984 __WEAK void vApplicationDaemonTaskStartupHook (void){}
2988 Dummy implementation of the callback function vApplicationStackOverflowHook().
2990 #if (configCHECK_FOR_STACK_OVERFLOW > 0)
2991 __WEAK void vApplicationStackOverflowHook (TaskHandle_t xTask, char *pcTaskName) {
2995 /* Assert when stack overflow is enabled but no application defined function exists */