]> begriffs open source - cmsis-freertos/blob - CMSIS/RTOS2/FreeRTOS/Source/cmsis_os2.c
Do not blindly restore lock state, but depend on the current state (#109)
[cmsis-freertos] / CMSIS / RTOS2 / FreeRTOS / Source / cmsis_os2.c
1 /* --------------------------------------------------------------------------
2  * Copyright (c) 2013-2024 Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
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
9  *
10  * www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  *      Name:    cmsis_os2.c
19  *      Purpose: CMSIS RTOS2 wrapper for FreeRTOS
20  *
21  *---------------------------------------------------------------------------*/
22
23 #include <string.h>
24
25 #include "cmsis_os2.h"                  // ::CMSIS:RTOS2
26 #include "cmsis_compiler.h"             // Compiler agnostic definitions
27 #include "os_tick.h"                    // OS Tick API
28
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
34
35 #include "freertos_mpool.h"             // osMemoryPool definitions
36 #include "freertos_os2.h"               // Configuration check and setup
37
38 /*---------------------------------------------------------------------------*/
39 #ifndef __ARM_ARCH_6M__
40   #define __ARM_ARCH_6M__         0
41 #endif
42 #ifndef __ARM_ARCH_7M__
43   #define __ARM_ARCH_7M__         0
44 #endif
45 #ifndef __ARM_ARCH_7EM__
46   #define __ARM_ARCH_7EM__        0
47 #endif
48 #ifndef __ARM_ARCH_8M_MAIN__
49   #define __ARM_ARCH_8M_MAIN__    0
50 #endif
51 #ifndef __ARM_ARCH_7A__
52   #define __ARM_ARCH_7A__         0
53 #endif
54
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)
62 /* CPSR mask bits */
63 #define CPSR_MASKBIT_I            0x80U
64
65 #define IS_IRQ_MASKED()           ((__get_CPSR() & CPSR_MASKBIT_I) != 0U)
66 #else
67 #define IS_IRQ_MASKED()           (__get_PRIMASK() != 0U)
68 #endif
69
70 #if    (__ARM_ARCH_7A__      == 1U)
71 /* CPSR mode bitmasks */
72 #define CPSR_MODE_USER            0x10U
73 #define CPSR_MODE_SYSTEM          0x1FU
74
75 #define IS_IRQ_MODE()             ((__get_mode() != CPSR_MODE_USER) && (__get_mode() != CPSR_MODE_SYSTEM))
76 #else
77 #define IS_IRQ_MODE()             (__get_IPSR() != 0U)
78 #endif
79
80 /* Limits */
81 #define MAX_BITS_TASK_NOTIFY      31U
82 #define MAX_BITS_EVENT_GROUPS     24U
83
84 #define THREAD_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_TASK_NOTIFY)  - 1U))
85 #define EVENT_FLAGS_INVALID_BITS  (~((1UL << MAX_BITS_EVENT_GROUPS) - 1U))
86
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))
91
92 #define KERNEL_ID                 ("FreeRTOS " tskKERNEL_VERSION_NUMBER)
93
94 /* Timer callback information structure definition */
95 typedef struct {
96   osTimerFunc_t func;
97   void         *arg;
98 } TimerCallback_t;
99
100 /* Kernel initialization state */
101 static osKernelState_t KernelState = osKernelInactive;
102
103 /*
104   Heap region definition used by heap_5 variant
105
106   Define configAPPLICATION_ALLOCATED_HEAP as nonzero value in FreeRTOSConfig.h if
107   heap regions are already defined and vPortDefineHeapRegions is called in application.
108
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.
112 */
113 #if defined(USE_FreeRTOS_HEAP_5)
114 #if (configAPPLICATION_ALLOCATED_HEAP == 0)
115   /*
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
119     HeapRegion_t array.
120   */
121   #define HEAP_5_REGION_SETUP   1
122   
123   #ifndef configHEAP_5_REGIONS
124     #define configHEAP_5_REGIONS xHeapRegions
125
126     static uint8_t ucHeap[configTOTAL_HEAP_SIZE];
127
128     static HeapRegion_t xHeapRegions[] = {
129       { ucHeap, configTOTAL_HEAP_SIZE },
130       { NULL,   0                     }
131     };
132   #else
133     /* Global definition is provided to override default heap array */
134     extern HeapRegion_t configHEAP_5_REGIONS[];
135   #endif
136 #else
137   /*
138     The application already defined the array used for the FreeRTOS heap and
139     called vPortDefineHeapRegions to initialize heap.
140   */
141   #define HEAP_5_REGION_SETUP   0
142 #endif /* configAPPLICATION_ALLOCATED_HEAP */
143 #endif /* USE_FreeRTOS_HEAP_5 */
144
145 #if defined(SysTick)
146 #undef SysTick_Handler
147
148 /* CMSIS SysTick interrupt handler prototype */
149 extern void SysTick_Handler     (void);
150 /* FreeRTOS tick timer interrupt handler prototype */
151 extern void xPortSysTickHandler (void);
152
153 /*
154   SysTick handler implementation that also clears overflow flag.
155 */
156 void SysTick_Handler (void) {
157 #if (configUSE_TICKLESS_IDLE == 0)
158   /* Clear overflow flag */
159   SysTick->CTRL;
160 #endif
161
162   if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
163     /* Call tick handler */
164     xPortSysTickHandler();
165   }
166 }
167 #endif /* SysTick */
168
169 /*
170   Determine if CPU executes from interrupt context or if interrupts are masked.
171 */
172 __STATIC_INLINE uint32_t IRQ_Context (void) {
173   uint32_t irq;
174   BaseType_t state;
175
176   irq = 0U;
177
178   if (IS_IRQ_MODE()) {
179     /* Called from interrupt context */
180     irq = 1U;
181   }
182   else {
183     /* Get FreeRTOS scheduler state */
184     state = xTaskGetSchedulerState();
185
186     if (state != taskSCHEDULER_NOT_STARTED) {
187       /* Scheduler was started */
188       if (IS_IRQ_MASKED()) {
189         /* Interrupts are masked */
190         irq = 1U;
191       }
192     }
193   }
194
195   /* Return context, 0: thread context, 1: IRQ context */
196   return (irq);
197 }
198
199
200 /* ==== Kernel Management Functions ==== */
201
202 /*
203   Initialize the RTOS Kernel.
204 */
205 osStatus_t osKernelInitialize (void) {
206   osStatus_t stat;
207   BaseType_t state;
208
209   if (IRQ_Context() != 0U) {
210     stat = osErrorISR;
211   }
212   else {
213     state = xTaskGetSchedulerState();
214
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);
220       #endif
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);
224       #endif
225       KernelState = osKernelReady;
226       stat = osOK;
227     } else {
228       stat = osError;
229     }
230   }
231
232   /* Return execution status */
233   return (stat);
234 }
235
236 /*
237   Get RTOS Kernel Information.
238 */
239 osStatus_t osKernelGetInfo (osVersion_t *version, char *id_buf, uint32_t id_size) {
240
241   if (version != NULL) {
242     /* Version encoding is major.minor.rev: mmnnnrrrr dec */
243     version->api    = KERNEL_VERSION;
244     version->kernel = KERNEL_VERSION;
245   }
246
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);
251     }
252     /* Copy kernel identification string into provided buffer */
253     memcpy(id_buf, KERNEL_ID, id_size);
254   }
255
256   /* Return execution status */
257   return (osOK);
258 }
259
260 /*
261   Get the current RTOS Kernel state.
262 */
263 osKernelState_t osKernelGetState (void) {
264   osKernelState_t state;
265
266   switch (xTaskGetSchedulerState()) {
267     case taskSCHEDULER_RUNNING:
268       state = osKernelRunning;
269       break;
270
271     case taskSCHEDULER_SUSPENDED:
272       state = osKernelLocked;
273       break;
274
275     case taskSCHEDULER_NOT_STARTED:
276     default:
277       if (KernelState == osKernelReady) {
278         /* Ready, osKernelInitialize was already called */
279         state = osKernelReady;
280       } else {
281         /* Not initialized */
282         state = osKernelInactive;
283       }
284       break;
285   }
286
287   /* Return current state */
288   return (state);
289 }
290
291 /*
292   Start the RTOS Kernel scheduler.
293 */
294 osStatus_t osKernelStart (void) {
295   osStatus_t stat;
296   BaseType_t state;
297
298   if (IRQ_Context() != 0U) {
299     stat = osErrorISR;
300   }
301   else {
302     state = xTaskGetSchedulerState();
303
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();
310       stat = osOK;
311     } else {
312       stat = osError;
313     }
314   }
315
316   /* Return execution status */
317   return (stat);
318 }
319
320 /*
321   Lock the RTOS Kernel scheduler.
322 */
323 int32_t osKernelLock (void) {
324   int32_t lock;
325
326   if (IRQ_Context() != 0U) {
327     lock = (int32_t)osErrorISR;
328   }
329   else {
330     switch (xTaskGetSchedulerState()) {
331       case taskSCHEDULER_SUSPENDED:
332         lock = 1;
333         break;
334
335       case taskSCHEDULER_RUNNING:
336         vTaskSuspendAll();
337         lock = 0;
338         break;
339
340       case taskSCHEDULER_NOT_STARTED:
341       default:
342         lock = (int32_t)osError;
343         break;
344     }
345   }
346
347   /* Return previous lock state */
348   return (lock);
349 }
350
351 /*
352   Unlock the RTOS Kernel scheduler.
353 */
354 int32_t osKernelUnlock (void) {
355   int32_t lock;
356
357   if (IRQ_Context() != 0U) {
358     lock = (int32_t)osErrorISR;
359   }
360   else {
361     switch (xTaskGetSchedulerState()) {
362       case taskSCHEDULER_SUSPENDED:
363         lock = 1;
364
365         if (xTaskResumeAll() != pdTRUE) {
366           if (xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED) {
367             lock = (int32_t)osError;
368           }
369         }
370         break;
371
372       case taskSCHEDULER_RUNNING:
373         lock = 0;
374         break;
375
376       case taskSCHEDULER_NOT_STARTED:
377       default:
378         lock = (int32_t)osError;
379         break;
380     }
381   }
382
383   /* Return previous lock state */
384   return (lock);
385 }
386
387 /*
388   Restore the RTOS Kernel scheduler lock state.
389 */
390 int32_t osKernelRestoreLock (int32_t lock) {
391
392   if (IRQ_Context() != 0U) {
393     lock = (int32_t)osErrorISR;
394   }
395   else {
396     switch (xTaskGetSchedulerState()) {
397       case taskSCHEDULER_SUSPENDED:
398         if (lock == 0) {
399           if (xTaskResumeAll() != pdTRUE) {
400             lock = (int32_t)osError;
401           }
402         }
403         else {
404           if (lock != 1) {
405             lock = (int32_t)osError;
406           }
407         }
408         break;
409
410       case taskSCHEDULER_RUNNING:
411         if (lock == 1) {
412           vTaskSuspendAll();
413         }
414         else {
415           if (lock != 0) {
416             lock = (int32_t)osError;
417           }
418         }
419         break;
420
421       case taskSCHEDULER_NOT_STARTED:
422       default:
423         lock = (int32_t)osError;
424         break;
425     }
426   }
427
428   /* Return new lock state */
429   return (lock);
430 }
431
432 /*
433   Get the RTOS kernel tick count.
434 */
435 uint32_t osKernelGetTickCount (void) {
436   TickType_t ticks;
437
438   if (IRQ_Context() != 0U) {
439     ticks = xTaskGetTickCountFromISR();
440   } else {
441     ticks = xTaskGetTickCount();
442   }
443
444   /* Return kernel tick count */
445   return (ticks);
446 }
447
448 /*
449   Get the RTOS kernel tick frequency.
450 */
451 uint32_t osKernelGetTickFreq (void) {
452   /* Return frequency in hertz */
453   return (configTICK_RATE_HZ);
454 }
455
456 /*
457   Get the RTOS kernel system timer count.
458 */
459 uint32_t osKernelGetSysTimerCount (void) {
460   uint32_t irqmask = IS_IRQ_MASKED();
461   TickType_t ticks;
462   uint32_t val;
463 #if (configUSE_TICKLESS_IDLE != 0)
464   uint32_t val0;
465
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();
473 #endif
474
475   if (irqmask == 0U) {
476     __disable_irq();
477   }
478
479   ticks = xTaskGetTickCount();
480   val   = OS_Tick_GetCount();
481
482   /* Update tick count and timer value when timer overflows */
483 #if (configUSE_TICKLESS_IDLE != 0)
484   if (val < val0) {
485     ticks++;
486   }
487 #else
488   if (OS_Tick_GetOverflow() != 0U) {
489     val = OS_Tick_GetCount();
490     ticks++;
491   }
492 #endif
493
494   val += ticks * OS_Tick_GetInterval();
495
496   if (irqmask == 0U) {
497     __enable_irq();
498   }
499
500   /* Return system timer count */
501   return (val);
502 }
503
504 /*
505   Get the RTOS kernel system timer frequency.
506 */
507 uint32_t osKernelGetSysTimerFreq (void) {
508   /* Return frequency in hertz */
509   return (configCPU_CLOCK_HZ);
510 }
511
512
513 /* ==== Thread Management Functions ==== */
514
515 /*
516   Create a thread and add it to Active Threads.
517
518   Limitations:
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.
522 */
523 osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr) {
524   const char *name;
525   uint32_t stack;
526   TaskHandle_t hTask;
527   UBaseType_t prio;
528   int32_t mem;
529 #if (configUSE_OS2_CPU_AFFINITY == 1)
530   UBaseType_t core_aff = tskNO_AFFINITY;
531 #endif
532
533   hTask = NULL;
534
535   if ((IRQ_Context() == 0U) && (func != NULL)) {
536     stack = configMINIMAL_STACK_SIZE;
537     prio  = (UBaseType_t)osPriorityNormal;
538
539     name = NULL;
540     mem  = -1;
541
542     if (attr != NULL) {
543       if (attr->name != NULL) {
544         name = attr->name;
545       }
546       if (attr->priority != osPriorityNone) {
547         prio = (UBaseType_t)attr->priority;
548       }
549
550       if ((prio < osPriorityIdle) || (prio > osPriorityISR) || ((attr->attr_bits & osThreadJoinable) == osThreadJoinable)) {
551         /* Invalid priority or unsupported osThreadJoinable attribute used */
552         return (NULL);
553       }
554
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);
559       }
560
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 */
564         mem = 1;
565       }
566       else {
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 */
569           mem = 0;
570         }
571       }
572
573       #if (configUSE_OS2_CPU_AFFINITY == 1)
574         if (attr->affinity_mask != 0U) {
575           core_aff = attr->affinity_mask;
576         }
577       #endif
578     }
579     else {
580       mem = 0;
581     }
582
583     if (mem == 1) {
584       #if (configSUPPORT_STATIC_ALLOCATION == 1)
585         #if (configUSE_OS2_CPU_AFFINITY == 0)
586           hTask = xTaskCreateStatic ((TaskFunction_t)func,
587                                                      name,
588                                                      stack,
589                                                      argument,
590                                                      prio - 1U,
591                                      (StackType_t  *)attr->stack_mem,
592                                      (StaticTask_t *)attr->cb_mem);
593         #else
594           hTask = xTaskCreateStaticAffinitySet ((TaskFunction_t)func,
595                                                                 name,
596                                                                 stack,
597                                                                 argument,
598                                                                 prio - 1U,
599                                                 (StackType_t  *)attr->stack_mem,
600                                                 (StaticTask_t *)attr->cb_mem,
601                                                                 core_aff);
602         #endif
603       #endif
604     }
605     else {
606       if (mem == 0) {
607         #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
608           #if (configUSE_OS2_CPU_AFFINITY == 0)
609             if (xTaskCreate ((TaskFunction_t        )func,
610                                                      name,
611                              (configSTACK_DEPTH_TYPE)stack,
612                                                      argument,
613                                                      prio - 1U,
614                                                      &hTask) != pdPASS) {
615               hTask = NULL;
616             }
617           #else
618             if (xTaskCreateAffinitySet ((TaskFunction_t        )func,
619                                                                 name,
620                                         (configSTACK_DEPTH_TYPE)stack,
621                                                                 argument,
622                                                                 prio - 1U,
623                                                                 core_aff,
624                                                                 &hTask) != pdPASS) {
625               hTask = NULL;
626             }
627           #endif
628         #endif
629       }
630     }
631   }
632
633   /* Return thread ID */
634   return ((osThreadId_t)hTask);
635 }
636
637 /*
638   Get name of a thread.
639 */
640 const char *osThreadGetName (osThreadId_t thread_id) {
641   TaskHandle_t hTask = (TaskHandle_t)thread_id;
642   const char *name;
643
644   if (hTask == NULL) {
645     name = NULL;
646   }
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);
651   }
652   else {
653     name = pcTaskGetName (hTask);
654   }
655
656   /* Return name as null-terminated string */
657   return (name);
658 }
659
660 /*
661   Return the thread ID of the current running thread.
662 */
663 osThreadId_t osThreadGetId (void) {
664   osThreadId_t id;
665
666   id = (osThreadId_t)xTaskGetCurrentTaskHandle();
667
668   /* Return thread ID */
669   return (id);
670 }
671
672 /*
673   Get current thread state of a thread.
674 */
675 osThreadState_t osThreadGetState (osThreadId_t thread_id) {
676   TaskHandle_t hTask = (TaskHandle_t)thread_id;
677   osThreadState_t state;
678
679   if ((IRQ_Context() != 0U) || (hTask == NULL)) {
680     state = osThreadError;
681   }
682   else {
683     switch (eTaskGetState (hTask)) {
684       case eRunning:   state = osThreadRunning;    break;
685       case eReady:     state = osThreadReady;      break;
686       case eBlocked:
687       case eSuspended: state = osThreadBlocked;    break;
688       case eDeleted:
689       case eInvalid:
690       default:         state = osThreadError;      break;
691     }
692   }
693
694   /* Return current thread state */
695   return (state);
696 }
697
698 /*
699   Get available stack space of a thread based on stack watermark recording during execution.
700 */
701 uint32_t osThreadGetStackSpace (osThreadId_t thread_id) {
702   TaskHandle_t hTask = (TaskHandle_t)thread_id;
703   uint32_t sz;
704
705   if ((IRQ_Context() != 0U) || (hTask == NULL)) {
706     sz = 0U;
707   } else {
708     sz = (uint32_t)(uxTaskGetStackHighWaterMark(hTask) * sizeof(StackType_t));
709   }
710
711   /* Return remaining stack space in bytes */
712   return (sz);
713 }
714
715 /*
716   Change priority of a thread.
717 */
718 osStatus_t osThreadSetPriority (osThreadId_t thread_id, osPriority_t priority) {
719   TaskHandle_t hTask = (TaskHandle_t)thread_id;
720   osStatus_t stat;
721
722   if (IRQ_Context() != 0U) {
723     stat = osErrorISR;
724   }
725   else if ((hTask == NULL) || (priority < osPriorityIdle) || (priority > osPriorityISR)) {
726     stat = osErrorParameter;
727   }
728   else {
729     stat = osOK;
730     vTaskPrioritySet (hTask, (UBaseType_t)priority - 1U);
731   }
732
733   /* Return execution status */
734   return (stat);
735 }
736
737 /*
738   Get current priority of a thread.
739 */
740 osPriority_t osThreadGetPriority (osThreadId_t thread_id) {
741   TaskHandle_t hTask = (TaskHandle_t)thread_id;
742   osPriority_t prio;
743
744   if ((IRQ_Context() != 0U) || (hTask == NULL)) {
745     prio = osPriorityError;
746   } else {
747     prio = (osPriority_t)(uxTaskPriorityGet (hTask) + 1U);
748   }
749
750   /* Return current thread priority */
751   return (prio);
752 }
753
754 /*
755   Pass control to next thread that is in state READY.
756 */
757 osStatus_t osThreadYield (void) {
758   osStatus_t stat;
759
760   if (IRQ_Context() != 0U) {
761     stat = osErrorISR;
762   } else {
763     stat = osOK;
764     taskYIELD();
765   }
766
767   /* Return execution status */
768   return (stat);
769 }
770
771 #if (configUSE_OS2_THREAD_SUSPEND_RESUME == 1)
772 /*
773   Suspend execution of a thread.
774 */
775 osStatus_t osThreadSuspend (osThreadId_t thread_id) {
776   TaskHandle_t hTask = (TaskHandle_t)thread_id;
777   osStatus_t stat;
778
779   if (IRQ_Context() != 0U) {
780     stat = osErrorISR;
781   }
782   else if (hTask == NULL) {
783     stat = osErrorParameter;
784   }
785   else {
786     stat = osOK;
787     vTaskSuspend (hTask);
788   }
789
790   /* Return execution status */
791   return (stat);
792 }
793
794 /*
795   Resume execution of a thread.
796 */
797 osStatus_t osThreadResume (osThreadId_t thread_id) {
798   TaskHandle_t hTask = (TaskHandle_t)thread_id;
799   osStatus_t stat;
800   eTaskState tstate;
801
802   if (IRQ_Context() != 0U) {
803     stat = osErrorISR;
804   }
805   else if (hTask == NULL) {
806     stat = osErrorParameter;
807   }
808   else {
809     tstate = eTaskGetState (hTask);
810
811     if (tstate == eSuspended) {
812       /* Thread is suspended */
813       stat = osOK;
814       vTaskResume (hTask);
815     } else {
816       /* Not suspended, might be blocked */
817       if (xTaskAbortDelay(hTask) == pdPASS) {
818         /* Thread was unblocked */
819         stat = osOK;
820       } else {
821         /* Thread was not blocked */
822         stat = osErrorResource;
823       }
824     }
825   }
826
827   /* Return execution status */
828   return (stat);
829 }
830 #endif /* (configUSE_OS2_THREAD_SUSPEND_RESUME == 1) */
831
832 /*
833   Terminate execution of current running thread.
834 */
835 __NO_RETURN void osThreadExit (void) {
836 #ifndef USE_FreeRTOS_HEAP_1
837   vTaskDelete (NULL);
838 #endif
839   for (;;);
840 }
841
842 /*
843   Terminate execution of a thread.
844 */
845 osStatus_t osThreadTerminate (osThreadId_t thread_id) {
846   TaskHandle_t hTask = (TaskHandle_t)thread_id;
847   osStatus_t stat;
848 #ifndef USE_FreeRTOS_HEAP_1
849   eTaskState tstate;
850
851   if (IRQ_Context() != 0U) {
852     stat = osErrorISR;
853   }
854   else if (hTask == NULL) {
855     stat = osErrorParameter;
856   }
857   else {
858     tstate = eTaskGetState (hTask);
859
860     if (tstate != eDeleted) {
861       stat = osOK;
862       vTaskDelete (hTask);
863     } else {
864       stat = osErrorResource;
865     }
866   }
867 #else
868   stat = osError;
869 #endif
870
871   /* Return execution status */
872   return (stat);
873 }
874
875 /*
876   Get number of active threads.
877 */
878 uint32_t osThreadGetCount (void) {
879   uint32_t count;
880
881   if (IRQ_Context() != 0U) {
882     count = 0U;
883   } else {
884     count = uxTaskGetNumberOfTasks();
885   }
886
887   /* Return number of active threads */
888   return (count);
889 }
890
891 #if (configUSE_OS2_THREAD_ENUMERATE == 1)
892 /*
893   Enumerate active threads.
894 */
895 uint32_t osThreadEnumerate (osThreadId_t *thread_array, uint32_t array_items) {
896   uint32_t i, count;
897   TaskStatus_t *task;
898
899   if ((IRQ_Context() != 0U) || (thread_array == NULL) || (array_items == 0U)) {
900     count = 0U;
901   } else {
902     vTaskSuspendAll();
903
904     /* Allocate memory on heap to temporarily store TaskStatus_t information */
905     count = uxTaskGetNumberOfTasks();
906     task  = pvPortMalloc (count * sizeof(TaskStatus_t));
907
908     if (task != NULL) {
909       /* Retrieve task status information */
910       count = uxTaskGetSystemState (task, count, NULL);
911
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;
915       }
916       count = i;
917     }
918     (void)xTaskResumeAll();
919
920     vPortFree (task);
921   }
922
923   /* Return number of enumerated threads */
924   return (count);
925 }
926 #endif /* (configUSE_OS2_THREAD_ENUMERATE == 1) */
927
928 #if (configUSE_OS2_CPU_AFFINITY == 1)
929 /*
930   Set processor affinity mask of a thread.
931 */
932 osStatus_t osThreadSetAffinityMask (osThreadId_t thread_id, uint32_t affinity_mask) {
933   TaskHandle_t hTask = (TaskHandle_t)thread_id;
934   osStatus_t stat;
935
936   if (IRQ_Context() != 0U) {
937     stat = osErrorISR;
938   }
939   else if (hTask == NULL) {
940     stat = osErrorParameter;
941   }
942   else {
943     stat = osOK;
944     vTaskCoreAffinitySet (hTask, (UBaseType_t)affinity_mask);
945   }
946
947   /* Return execution status */
948   return (stat);
949 }
950
951 /*
952   Get current processor affinity mask of a thread.
953 */
954 uint32_t osThreadGetAffinityMask (osThreadId_t thread_id) {
955   TaskHandle_t hTask = (TaskHandle_t)thread_id;
956   UBaseType_t affinity_mask;
957
958   if (IRQ_Context() != 0U) {
959     affinity_mask = 0U;
960   }
961   else if (hTask == NULL) {
962     affinity_mask = 0U;
963   }
964   else {
965     affinity_mask = vTaskCoreAffinityGet (hTask);
966   }
967
968   /* Return current processor affinity mask */
969   return ((uint32_t)affinity_mask);
970 }
971 #endif /* (configUSE_OS2_CPU_AFFINITY == 1) */
972
973 /* ==== Thread Flags Functions ==== */
974
975 #if (configUSE_OS2_THREAD_FLAGS == 1)
976 /*
977   Set the specified Thread Flags of a thread.
978 */
979 uint32_t osThreadFlagsSet (osThreadId_t thread_id, uint32_t flags) {
980   TaskHandle_t hTask = (TaskHandle_t)thread_id;
981   uint32_t rflags;
982   BaseType_t yield;
983
984   if ((hTask == NULL) || ((flags & THREAD_FLAGS_INVALID_BITS) != 0U)) {
985     rflags = (uint32_t)osErrorParameter;
986   }
987   else {
988     rflags = (uint32_t)osError;
989
990     if (IRQ_Context() != 0U) {
991       yield = pdFALSE;
992
993       (void)xTaskNotifyFromISR (hTask, flags, eSetBits, &yield);
994       (void)xTaskNotifyAndQueryFromISR (hTask, 0, eNoAction, &rflags, NULL);
995
996       portYIELD_FROM_ISR (yield);
997     }
998     else {
999       (void)xTaskNotify (hTask, flags, eSetBits);
1000       (void)xTaskNotifyAndQuery (hTask, 0, eNoAction, &rflags);
1001     }
1002   }
1003   /* Return flags after setting */
1004   return (rflags);
1005 }
1006
1007 /*
1008   Clear the specified Thread Flags of current running thread.
1009 */
1010 uint32_t osThreadFlagsClear (uint32_t flags) {
1011   TaskHandle_t hTask;
1012   uint32_t rflags, cflags;
1013
1014   if (IRQ_Context() != 0U) {
1015     rflags = (uint32_t)osErrorISR;
1016   }
1017   else if ((flags & THREAD_FLAGS_INVALID_BITS) != 0U) {
1018     rflags = (uint32_t)osErrorParameter;
1019   }
1020   else {
1021     hTask = xTaskGetCurrentTaskHandle();
1022
1023     if (xTaskNotifyAndQuery (hTask, 0, eNoAction, &cflags) == pdPASS) {
1024       rflags = cflags;
1025       cflags &= ~flags;
1026
1027       if (xTaskNotify (hTask, cflags, eSetValueWithOverwrite) != pdPASS) {
1028         rflags = (uint32_t)osError;
1029       }
1030     }
1031     else {
1032       rflags = (uint32_t)osError;
1033     }
1034   }
1035
1036   /* Return flags before clearing */
1037   return (rflags);
1038 }
1039
1040 /*
1041   Get the current Thread Flags of current running thread.
1042 */
1043 uint32_t osThreadFlagsGet (void) {
1044   TaskHandle_t hTask;
1045   uint32_t rflags;
1046
1047   if (IRQ_Context() != 0U) {
1048     rflags = (uint32_t)osErrorISR;
1049   }
1050   else {
1051     hTask = xTaskGetCurrentTaskHandle();
1052
1053     if (xTaskNotifyAndQuery (hTask, 0, eNoAction, &rflags) != pdPASS) {
1054       rflags = (uint32_t)osError;
1055     }
1056   }
1057
1058   /* Return current flags */
1059   return (rflags);
1060 }
1061
1062 /*
1063   Wait for one or more Thread Flags of the current running thread to become signaled.
1064 */
1065 uint32_t osThreadFlagsWait (uint32_t flags, uint32_t options, uint32_t timeout) {
1066   TaskHandle_t hTask;
1067   uint32_t rflags, nval;
1068   uint32_t clear;
1069   TickType_t t0, td, tout;
1070   BaseType_t rval;
1071   BaseType_t notify = pdFALSE;
1072
1073   if (IRQ_Context() != 0U) {
1074     rflags = (uint32_t)osErrorISR;
1075   }
1076   else if ((flags & THREAD_FLAGS_INVALID_BITS) != 0U) {
1077     rflags = (uint32_t)osErrorParameter;
1078   }
1079   else {
1080     if ((options & osFlagsNoClear) == osFlagsNoClear) {
1081       clear = 0U;
1082     } else {
1083       clear = flags;
1084     }
1085
1086     rflags = 0U;
1087     tout   = timeout;
1088
1089     t0 = xTaskGetTickCount();
1090     do {
1091       rval = xTaskNotifyWait (0, clear, &nval, tout);
1092
1093       if (rval == pdPASS) {
1094         rflags &= flags;
1095         rflags |= nval;
1096
1097         if ((rflags & ~flags) != 0) {
1098           /* Other flags already set, notify task to change its state */
1099           notify = pdTRUE;
1100         }
1101
1102         if ((options & osFlagsWaitAll) == osFlagsWaitAll) {
1103           if ((flags & rflags) == flags) {
1104             break;
1105           } else {
1106             if (timeout == 0U) {
1107               rflags = (uint32_t)osErrorResource;
1108               break;
1109             }
1110           }
1111         }
1112         else {
1113           if ((flags & rflags) != 0) {
1114             break;
1115           } else {
1116             if (timeout == 0U) {
1117               rflags = (uint32_t)osErrorResource;
1118               break;
1119             }
1120           }
1121         }
1122
1123         /* Update timeout */
1124         td = xTaskGetTickCount() - t0;
1125
1126         if (td > timeout) {
1127           tout  = 0;
1128         } else {
1129           tout = timeout - td;
1130         }
1131       }
1132       else {
1133         if (timeout == 0) {
1134           rflags = (uint32_t)osErrorResource;
1135         } else {
1136           rflags = (uint32_t)osErrorTimeout;
1137         }
1138       }
1139     }
1140     while (rval != pdFAIL);
1141   }
1142
1143   if (notify == pdTRUE) {
1144     hTask = xTaskGetCurrentTaskHandle();
1145
1146     /* Ensure task is already notified without changing existing flags */
1147     if (xTaskNotify(hTask, 0, eNoAction) != pdPASS) {
1148       rflags = (uint32_t)osError;
1149     }
1150   }
1151
1152   /* Return flags before clearing */
1153   return (rflags);
1154 }
1155 #endif /* (configUSE_OS2_THREAD_FLAGS == 1) */
1156
1157
1158 /* ==== Generic Wait Functions ==== */
1159
1160 /*
1161   Wait for Timeout (Time Delay).
1162 */
1163 osStatus_t osDelay (uint32_t ticks) {
1164   osStatus_t stat;
1165
1166   if (IRQ_Context() != 0U) {
1167     stat = osErrorISR;
1168   }
1169   else {
1170     stat = osOK;
1171
1172     if (ticks != 0U) {
1173       vTaskDelay(ticks);
1174     }
1175   }
1176
1177   /* Return execution status */
1178   return (stat);
1179 }
1180
1181 /*
1182   Wait until specified time.
1183 */
1184 osStatus_t osDelayUntil (uint32_t ticks) {
1185   TickType_t tcnt, delay;
1186   osStatus_t stat;
1187
1188   if (IRQ_Context() != 0U) {
1189     stat = osErrorISR;
1190   }
1191   else {
1192     stat = osOK;
1193     tcnt = xTaskGetTickCount();
1194
1195     /* Determine remaining number of ticks to delay */
1196     delay = (TickType_t)ticks - tcnt;
1197
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) {
1201         /* Did not delay */
1202         stat = osError;
1203       }
1204     }
1205     else
1206     {
1207       /* No delay or already expired */
1208       stat = osErrorParameter;
1209     }
1210   }
1211
1212   /* Return execution status */
1213   return (stat);
1214 }
1215
1216
1217 /* ==== Timer Management Functions ==== */
1218
1219 #if (configUSE_OS2_TIMER == 1)
1220
1221 static void TimerCallback (TimerHandle_t hTimer) {
1222   TimerCallback_t *callb;
1223
1224   /* Retrieve pointer to callback function and argument */
1225   callb = (TimerCallback_t *)pvTimerGetTimerID (hTimer);
1226
1227   /* Remove dynamic allocation flag */
1228   callb = (TimerCallback_t *)((uint32_t)callb & ~1U);
1229
1230   if (callb != NULL) {
1231     callb->func (callb->arg);
1232   }
1233 }
1234
1235 /*
1236   Create and Initialize a timer.
1237 */
1238 osTimerId_t osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr) {
1239   const char *name;
1240   TimerHandle_t hTimer;
1241   TimerCallback_t *callb;
1242   UBaseType_t reload;
1243   int32_t mem;
1244   uint32_t callb_dyn;
1245
1246   hTimer = NULL;
1247
1248   if ((IRQ_Context() == 0U) && (func != NULL)) {
1249     callb     = NULL;
1250     callb_dyn = 0U;
1251
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));
1258         }
1259       }
1260     #endif
1261
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));
1267
1268         if (callb != NULL) {
1269           /* Callback memory was allocated from dynamic pool, set flag */
1270           callb_dyn = 1U;
1271         }
1272       }
1273     #endif
1274
1275     if (callb != NULL) {
1276       callb->func = func;
1277       callb->arg  = argument;
1278
1279       if (type == osTimerOnce) {
1280         reload = pdFALSE;
1281       } else {
1282         reload = pdTRUE;
1283       }
1284
1285       mem  = -1;
1286       name = NULL;
1287
1288       if (attr != NULL) {
1289         if (attr->name != NULL) {
1290           name = attr->name;
1291         }
1292
1293         if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticTimer_t))) {
1294           /* The memory for control block is provided, use static object */
1295           mem = 1;
1296         }
1297         else {
1298           if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
1299             /* Control block will be allocated from the dynamic pool */
1300             mem = 0;
1301           }
1302         }
1303       }
1304       else {
1305         mem = 0;
1306       }
1307       /* Store callback memory dynamic allocation flag */
1308       callb = (TimerCallback_t *)((uint32_t)callb | callb_dyn);
1309       /*
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.
1312       */
1313       if (mem == 1) {
1314         #if (configSUPPORT_STATIC_ALLOCATION == 1)
1315           hTimer = xTimerCreateStatic (name, 1, reload, callb, TimerCallback, (StaticTimer_t *)attr->cb_mem);
1316         #endif
1317       }
1318       else {
1319         if (mem == 0) {
1320           #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
1321             hTimer = xTimerCreate (name, 1, reload, callb, TimerCallback);
1322           #endif
1323         }
1324       }
1325
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);
1330
1331         vPortFree (callb);
1332       }
1333       #endif
1334     }
1335   }
1336
1337   /* Return timer ID */
1338   return ((osTimerId_t)hTimer);
1339 }
1340
1341 /*
1342   Get name of a timer.
1343 */
1344 const char *osTimerGetName (osTimerId_t timer_id) {
1345   TimerHandle_t hTimer = (TimerHandle_t)timer_id;
1346   const char *p;
1347
1348   if (hTimer == NULL) {
1349     p = NULL;
1350   }
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);
1355   }
1356   else {
1357     p = pcTimerGetName (hTimer);
1358   }
1359
1360   /* Return name as null-terminated string */
1361   return (p);
1362 }
1363
1364 /*
1365   Start or restart a timer.
1366 */
1367 osStatus_t osTimerStart (osTimerId_t timer_id, uint32_t ticks) {
1368   TimerHandle_t hTimer = (TimerHandle_t)timer_id;
1369   osStatus_t stat;
1370
1371   if (IRQ_Context() != 0U) {
1372     stat = osErrorISR;
1373   }
1374   else if ((hTimer == NULL) || (ticks == 0U)) {
1375     stat = osErrorParameter;
1376   }
1377   else {
1378     if (xTimerChangePeriod (hTimer, ticks, 0) == pdPASS) {
1379       stat = osOK;
1380     } else {
1381       stat = osErrorResource;
1382     }
1383   }
1384
1385   /* Return execution status */
1386   return (stat);
1387 }
1388
1389 /*
1390   Stop a timer.
1391 */
1392 osStatus_t osTimerStop (osTimerId_t timer_id) {
1393   TimerHandle_t hTimer = (TimerHandle_t)timer_id;
1394   osStatus_t stat;
1395
1396   if (IRQ_Context() != 0U) {
1397     stat = osErrorISR;
1398   }
1399   else if (hTimer == NULL) {
1400     stat = osErrorParameter;
1401   }
1402   else {
1403     if (xTimerIsTimerActive (hTimer) == pdFALSE) {
1404       stat = osErrorResource;
1405     }
1406     else {
1407       if (xTimerStop (hTimer, 0) == pdPASS) {
1408         stat = osOK;
1409       } else {
1410         stat = osError;
1411       }
1412     }
1413   }
1414
1415   /* Return execution status */
1416   return (stat);
1417 }
1418
1419 /*
1420   Check if a timer is running.
1421 */
1422 uint32_t osTimerIsRunning (osTimerId_t timer_id) {
1423   TimerHandle_t hTimer = (TimerHandle_t)timer_id;
1424   uint32_t running;
1425
1426   if ((IRQ_Context() != 0U) || (hTimer == NULL)) {
1427     running = 0U;
1428   } else {
1429     running = (uint32_t)xTimerIsTimerActive (hTimer);
1430   }
1431
1432   /* Return 0: not running, 1: running */
1433   return (running);
1434 }
1435
1436 /*
1437   Delete a timer.
1438 */
1439 osStatus_t osTimerDelete (osTimerId_t timer_id) {
1440   TimerHandle_t hTimer = (TimerHandle_t)timer_id;
1441   osStatus_t stat;
1442 #ifndef USE_FreeRTOS_HEAP_1
1443 #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
1444   TimerCallback_t *callb;
1445 #endif
1446
1447   if (IRQ_Context() != 0U) {
1448     stat = osErrorISR;
1449   }
1450   else if (hTimer == NULL) {
1451     stat = osErrorParameter;
1452   }
1453   else {
1454     #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
1455     callb = (TimerCallback_t *)pvTimerGetTimerID (hTimer);
1456     #endif
1457
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);
1463
1464           /* Return allocated memory to dynamic pool */
1465           vPortFree (callb);
1466         }
1467       #endif
1468       stat = osOK;
1469     } else {
1470       stat = osErrorResource;
1471     }
1472   }
1473 #else
1474   stat = osError;
1475 #endif
1476
1477   /* Return execution status */
1478   return (stat);
1479 }
1480 #endif /* (configUSE_OS2_TIMER == 1) */
1481
1482
1483 /* ==== Event Flags Management Functions ==== */
1484
1485 /*
1486   Create and Initialize an Event Flags object.
1487
1488   Limitations:
1489   - Event flags are limited to 24 bits.
1490 */
1491 osEventFlagsId_t osEventFlagsNew (const osEventFlagsAttr_t *attr) {
1492   EventGroupHandle_t hEventGroup;
1493   int32_t mem;
1494
1495   hEventGroup = NULL;
1496
1497   if (IRQ_Context() == 0U) {
1498     mem = -1;
1499
1500     if (attr != NULL) {
1501       if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticEventGroup_t))) {
1502         /* The memory for control block is provided, use static object */
1503         mem = 1;
1504       }
1505       else {
1506         if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
1507           /* Control block will be allocated from the dynamic pool */
1508           mem = 0;
1509         }
1510       }
1511     }
1512     else {
1513       mem = 0;
1514     }
1515
1516     if (mem == 1) {
1517       #if (configSUPPORT_STATIC_ALLOCATION == 1)
1518       hEventGroup = xEventGroupCreateStatic (attr->cb_mem);
1519       #endif
1520     }
1521     else {
1522       if (mem == 0) {
1523         #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
1524           hEventGroup = xEventGroupCreate();
1525         #endif
1526       }
1527     }
1528   }
1529
1530   /* Return event flags ID */
1531   return ((osEventFlagsId_t)hEventGroup);
1532 }
1533
1534 /*
1535   Set the specified Event Flags.
1536
1537   Limitations:
1538   - Event flags are limited to 24 bits.
1539 */
1540 uint32_t osEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags) {
1541   EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
1542   uint32_t rflags;
1543   BaseType_t yield;
1544
1545   if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) {
1546     rflags = (uint32_t)osErrorParameter;
1547   }
1548   else if (IRQ_Context() != 0U) {
1549   #if (configUSE_OS2_EVENTFLAGS_FROM_ISR == 0)
1550     (void)yield;
1551     /* Enable timers and xTimerPendFunctionCall function to support osEventFlagsSet from ISR */
1552     rflags = (uint32_t)osErrorResource;
1553   #else
1554     yield = pdFALSE;
1555
1556     if (xEventGroupSetBitsFromISR (hEventGroup, (EventBits_t)flags, &yield) == pdFAIL) {
1557       rflags = (uint32_t)osErrorResource;
1558     } else {
1559       /* Retrieve bits that are already set and add flags to be set in current call */
1560       rflags  = xEventGroupGetBitsFromISR (hEventGroup);
1561       rflags |= flags;
1562       portYIELD_FROM_ISR (yield);
1563     }
1564   #endif
1565   }
1566   else {
1567     rflags = xEventGroupSetBits (hEventGroup, (EventBits_t)flags);
1568   }
1569
1570   /* Return event flags after setting */
1571   return (rflags);
1572 }
1573
1574 /*
1575   Clear the specified Event Flags.
1576
1577   Limitations:
1578   - Event flags are limited to 24 bits.
1579 */
1580 uint32_t osEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags) {
1581   EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
1582   uint32_t rflags;
1583
1584   if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) {
1585     rflags = (uint32_t)osErrorParameter;
1586   }
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;
1591   #else
1592     rflags = xEventGroupGetBitsFromISR (hEventGroup);
1593
1594     if (xEventGroupClearBitsFromISR (hEventGroup, (EventBits_t)flags) == pdFAIL) {
1595       rflags = (uint32_t)osErrorResource;
1596     }
1597     else {
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);
1602     }
1603   #endif
1604   }
1605   else {
1606     rflags = xEventGroupClearBits (hEventGroup, (EventBits_t)flags);
1607   }
1608
1609   /* Return event flags before clearing */
1610   return (rflags);
1611 }
1612
1613 /*
1614   Get the current Event Flags.
1615
1616   Limitations:
1617   - Event flags are limited to 24 bits.
1618 */
1619 uint32_t osEventFlagsGet (osEventFlagsId_t ef_id) {
1620   EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
1621   uint32_t rflags;
1622
1623   if (ef_id == NULL) {
1624     rflags = 0U;
1625   }
1626   else if (IRQ_Context() != 0U) {
1627     rflags = xEventGroupGetBitsFromISR (hEventGroup);
1628   }
1629   else {
1630     rflags = xEventGroupGetBits (hEventGroup);
1631   }
1632
1633   /* Return current event flags */
1634   return (rflags);
1635 }
1636
1637 /*
1638   Wait for one or more Event Flags to become signaled.
1639
1640   Limitations:
1641   - Event flags are limited to 24 bits.
1642   - osEventFlagsWait cannot be called from an ISR.
1643 */
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;
1648   uint32_t rflags;
1649
1650   if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) {
1651     rflags = (uint32_t)osErrorParameter;
1652   }
1653   else if (IRQ_Context() != 0U) {
1654     if (timeout == 0U) {
1655       /* Try semantic is not supported */
1656       rflags = (uint32_t)osErrorISR;
1657     } else {
1658       /* Calling osEventFlagsWait from ISR with non-zero timeout is invalid */
1659       rflags = (uint32_t)osFlagsErrorParameter;
1660     }
1661   }
1662   else {
1663     if (options & osFlagsWaitAll) {
1664       wait_all = pdTRUE;
1665     } else {
1666       wait_all = pdFAIL;
1667     }
1668
1669     if (options & osFlagsNoClear) {
1670       exit_clr = pdFAIL;
1671     } else {
1672       exit_clr = pdTRUE;
1673     }
1674
1675     rflags = xEventGroupWaitBits (hEventGroup, (EventBits_t)flags, exit_clr, wait_all, (TickType_t)timeout);
1676
1677     if (options & osFlagsWaitAll) {
1678       if ((flags & rflags) != flags) {
1679         if (timeout > 0U) {
1680           rflags = (uint32_t)osErrorTimeout;
1681         } else {
1682           rflags = (uint32_t)osErrorResource;
1683         }
1684       }
1685     }
1686     else {
1687       if ((flags & rflags) == 0U) {
1688         if (timeout > 0U) {
1689           rflags = (uint32_t)osErrorTimeout;
1690         } else {
1691           rflags = (uint32_t)osErrorResource;
1692         }
1693       }
1694     }
1695   }
1696
1697   /* Return event flags before clearing */
1698   return (rflags);
1699 }
1700
1701 /*
1702   Delete an Event Flags object.
1703 */
1704 osStatus_t osEventFlagsDelete (osEventFlagsId_t ef_id) {
1705   EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
1706   osStatus_t stat;
1707
1708 #ifndef USE_FreeRTOS_HEAP_1
1709   if (IRQ_Context() != 0U) {
1710     stat = osErrorISR;
1711   }
1712   else if (hEventGroup == NULL) {
1713     stat = osErrorParameter;
1714   }
1715   else {
1716     stat = osOK;
1717     vEventGroupDelete (hEventGroup);
1718   }
1719 #else
1720   stat = osError;
1721 #endif
1722
1723   /* Return execution status */
1724   return (stat);
1725 }
1726
1727
1728 /* ==== Mutex Management Functions ==== */
1729
1730 #if (configUSE_OS2_MUTEX == 1)
1731 /*
1732   Create and Initialize a Mutex object.
1733
1734   Limitations:
1735   - Priority inherit protocol is used by default, osMutexPrioInherit attribute is ignored.
1736   - Robust mutex is not supported, NULL is returned if used.
1737 */
1738 osMutexId_t osMutexNew (const osMutexAttr_t *attr) {
1739   SemaphoreHandle_t hMutex;
1740   uint32_t type;
1741   uint32_t rmtx;
1742   int32_t  mem;
1743
1744   hMutex = NULL;
1745
1746   if (IRQ_Context() == 0U) {
1747     if (attr != NULL) {
1748       type = attr->attr_bits;
1749     } else {
1750       type = 0U;
1751     }
1752
1753     if ((type & osMutexRecursive) == osMutexRecursive) {
1754       rmtx = 1U;
1755     } else {
1756       rmtx = 0U;
1757     }
1758
1759     if ((type & osMutexRobust) != osMutexRobust) {
1760       mem = -1;
1761
1762       if (attr != NULL) {
1763         if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) {
1764           /* The memory for control block is provided, use static object */
1765           mem = 1;
1766         }
1767         else {
1768           if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
1769             /* Control block will be allocated from the dynamic pool */
1770             mem = 0;
1771           }
1772         }
1773       }
1774       else {
1775         mem = 0;
1776       }
1777
1778       if (mem == 1) {
1779         #if (configSUPPORT_STATIC_ALLOCATION == 1)
1780           if (rmtx != 0U) {
1781             #if (configUSE_RECURSIVE_MUTEXES == 1)
1782             hMutex = xSemaphoreCreateRecursiveMutexStatic (attr->cb_mem);
1783             #endif
1784           }
1785           else {
1786             hMutex = xSemaphoreCreateMutexStatic (attr->cb_mem);
1787           }
1788         #endif
1789       }
1790       else {
1791         if (mem == 0) {
1792           #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
1793             if (rmtx != 0U) {
1794               #if (configUSE_RECURSIVE_MUTEXES == 1)
1795               hMutex = xSemaphoreCreateRecursiveMutex ();
1796               #endif
1797             } else {
1798               hMutex = xSemaphoreCreateMutex ();
1799             }
1800           #endif
1801         }
1802       }
1803
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);
1809         }
1810       }
1811       #endif
1812
1813       if ((hMutex != NULL) && (rmtx != 0U)) {
1814         /* Set LSB as 'recursive mutex flag' */
1815         hMutex = (SemaphoreHandle_t)((uint32_t)hMutex | 1U);
1816       }
1817     }
1818   }
1819
1820   /* Return mutex ID */
1821   return ((osMutexId_t)hMutex);
1822 }
1823
1824 /*
1825   Acquire a Mutex or timeout if it is locked.
1826 */
1827 osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) {
1828   SemaphoreHandle_t hMutex;
1829   osStatus_t stat;
1830   uint32_t rmtx;
1831
1832   hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
1833
1834   /* Extract recursive mutex flag */
1835   rmtx = (uint32_t)mutex_id & 1U;
1836
1837   stat = osOK;
1838
1839   if (IRQ_Context() != 0U) {
1840     stat = osErrorISR;
1841   }
1842   else if (hMutex == NULL) {
1843     stat = osErrorParameter;
1844   }
1845   else {
1846     if (rmtx != 0U) {
1847       #if (configUSE_RECURSIVE_MUTEXES == 1)
1848       if (xSemaphoreTakeRecursive (hMutex, timeout) != pdPASS) {
1849         if (timeout != 0U) {
1850           stat = osErrorTimeout;
1851         } else {
1852           stat = osErrorResource;
1853         }
1854       }
1855       #endif
1856     }
1857     else {
1858       if (xSemaphoreTake (hMutex, timeout) != pdPASS) {
1859         if (timeout != 0U) {
1860           stat = osErrorTimeout;
1861         } else {
1862           stat = osErrorResource;
1863         }
1864       }
1865     }
1866   }
1867
1868   /* Return execution status */
1869   return (stat);
1870 }
1871
1872 /*
1873   Release a Mutex that was acquired by osMutexAcquire.
1874 */
1875 osStatus_t osMutexRelease (osMutexId_t mutex_id) {
1876   SemaphoreHandle_t hMutex;
1877   osStatus_t stat;
1878   uint32_t rmtx;
1879
1880   hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
1881
1882   /* Extract recursive mutex flag */
1883   rmtx = (uint32_t)mutex_id & 1U;
1884
1885   stat = osOK;
1886
1887   if (IRQ_Context() != 0U) {
1888     stat = osErrorISR;
1889   }
1890   else if (hMutex == NULL) {
1891     stat = osErrorParameter;
1892   }
1893   else {
1894     if (rmtx != 0U) {
1895       #if (configUSE_RECURSIVE_MUTEXES == 1)
1896       if (xSemaphoreGiveRecursive (hMutex) != pdPASS) {
1897         stat = osErrorResource;
1898       }
1899       #endif
1900     }
1901     else {
1902       if (xSemaphoreGive (hMutex) != pdPASS) {
1903         stat = osErrorResource;
1904       }
1905     }
1906   }
1907
1908   /* Return execution status */
1909   return (stat);
1910 }
1911
1912 /*
1913   Get Thread which owns a Mutex object.
1914 */
1915 osThreadId_t osMutexGetOwner (osMutexId_t mutex_id) {
1916   SemaphoreHandle_t hMutex;
1917   osThreadId_t owner;
1918
1919   hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
1920
1921   if ((IRQ_Context() != 0U) || (hMutex == NULL)) {
1922     owner = NULL;
1923   } else {
1924     owner = (osThreadId_t)xSemaphoreGetMutexHolder (hMutex);
1925   }
1926
1927   /* Return owner thread ID */
1928   return (owner);
1929 }
1930
1931 /*
1932   Delete a Mutex object.
1933 */
1934 osStatus_t osMutexDelete (osMutexId_t mutex_id) {
1935   osStatus_t stat;
1936 #ifndef USE_FreeRTOS_HEAP_1
1937   SemaphoreHandle_t hMutex;
1938
1939   hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
1940
1941   if (IRQ_Context() != 0U) {
1942     stat = osErrorISR;
1943   }
1944   else if (hMutex == NULL) {
1945     stat = osErrorParameter;
1946   }
1947   else {
1948     #if (configQUEUE_REGISTRY_SIZE > 0)
1949     vQueueUnregisterQueue (hMutex);
1950     #endif
1951     stat = osOK;
1952     vSemaphoreDelete (hMutex);
1953   }
1954 #else
1955   stat = osError;
1956 #endif
1957
1958   /* Return execution status */
1959   return (stat);
1960 }
1961 #endif /* (configUSE_OS2_MUTEX == 1) */
1962
1963
1964 /* ==== Semaphore Management Functions ==== */
1965
1966 /*
1967   Create and Initialize a Semaphore object.
1968 */
1969 osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) {
1970   SemaphoreHandle_t hSemaphore;
1971   int32_t mem;
1972
1973   hSemaphore = NULL;
1974
1975   if ((IRQ_Context() == 0U) && (max_count > 0U) && (initial_count <= max_count)) {
1976     mem = -1;
1977
1978     if (attr != NULL) {
1979       if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) {
1980         /* The memory for control block is provided, use static object */
1981         mem = 1;
1982       }
1983       else {
1984         if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
1985           /* Control block will be allocated from the dynamic pool */
1986           mem = 0;
1987         }
1988       }
1989     }
1990     else {
1991       mem = 0;
1992     }
1993
1994     if (mem != -1) {
1995       if (max_count == 1U) {
1996         if (mem == 1) {
1997           #if (configSUPPORT_STATIC_ALLOCATION == 1)
1998             hSemaphore = xSemaphoreCreateBinaryStatic ((StaticSemaphore_t *)attr->cb_mem);
1999           #endif
2000         }
2001         else {
2002           #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
2003             hSemaphore = xSemaphoreCreateBinary();
2004           #endif
2005         }
2006
2007         if ((hSemaphore != NULL) && (initial_count != 0U)) {
2008           if (xSemaphoreGive (hSemaphore) != pdPASS) {
2009             vSemaphoreDelete (hSemaphore);
2010             hSemaphore = NULL;
2011           }
2012         }
2013       }
2014       else {
2015         if (mem == 1) {
2016           #if (configSUPPORT_STATIC_ALLOCATION == 1)
2017             hSemaphore = xSemaphoreCreateCountingStatic (max_count, initial_count, (StaticSemaphore_t *)attr->cb_mem);
2018           #endif
2019         }
2020         else {
2021           #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
2022             hSemaphore = xSemaphoreCreateCounting (max_count, initial_count);
2023           #endif
2024         }
2025       }
2026       
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);
2032         }
2033       }
2034       #endif
2035     }
2036   }
2037
2038   /* Return semaphore ID */
2039   return ((osSemaphoreId_t)hSemaphore);
2040 }
2041
2042 /*
2043   Acquire a Semaphore token or timeout if no tokens are available.
2044 */
2045 osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) {
2046   SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
2047   osStatus_t stat;
2048   BaseType_t yield;
2049
2050   stat = osOK;
2051
2052   if (hSemaphore == NULL) {
2053     stat = osErrorParameter;
2054   }
2055   else if (IRQ_Context() != 0U) {
2056     if (timeout != 0U) {
2057       stat = osErrorParameter;
2058     }
2059     else {
2060       yield = pdFALSE;
2061
2062       if (xSemaphoreTakeFromISR (hSemaphore, &yield) != pdPASS) {
2063         stat = osErrorResource;
2064       } else {
2065         portYIELD_FROM_ISR (yield);
2066       }
2067     }
2068   }
2069   else {
2070     if (xSemaphoreTake (hSemaphore, (TickType_t)timeout) != pdPASS) {
2071       if (timeout != 0U) {
2072         stat = osErrorTimeout;
2073       } else {
2074         stat = osErrorResource;
2075       }
2076     }
2077   }
2078
2079   /* Return execution status */
2080   return (stat);
2081 }
2082
2083 /*
2084   Release a Semaphore token up to the initial maximum count.
2085 */
2086 osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id) {
2087   SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
2088   osStatus_t stat;
2089   BaseType_t yield;
2090
2091   stat = osOK;
2092
2093   if (hSemaphore == NULL) {
2094     stat = osErrorParameter;
2095   }
2096   else if (IRQ_Context() != 0U) {
2097     yield = pdFALSE;
2098
2099     if (xSemaphoreGiveFromISR (hSemaphore, &yield) != pdTRUE) {
2100       stat = osErrorResource;
2101     } else {
2102       portYIELD_FROM_ISR (yield);
2103     }
2104   }
2105   else {
2106     if (xSemaphoreGive (hSemaphore) != pdPASS) {
2107       stat = osErrorResource;
2108     }
2109   }
2110
2111   /* Return execution status */
2112   return (stat);
2113 }
2114
2115 /*
2116   Get current Semaphore token count.
2117 */
2118 uint32_t osSemaphoreGetCount (osSemaphoreId_t semaphore_id) {
2119   SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
2120   uint32_t count;
2121
2122   if (hSemaphore == NULL) {
2123     count = 0U;
2124   }
2125   else if (IRQ_Context() != 0U) {
2126     count = (uint32_t)uxSemaphoreGetCountFromISR (hSemaphore);
2127   } else {
2128     count = (uint32_t)uxSemaphoreGetCount (hSemaphore);
2129   }
2130
2131   /* Return number of tokens */
2132   return (count);
2133 }
2134
2135 /*
2136   Delete a Semaphore object.
2137 */
2138 osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id) {
2139   SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
2140   osStatus_t stat;
2141
2142 #ifndef USE_FreeRTOS_HEAP_1
2143   if (IRQ_Context() != 0U) {
2144     stat = osErrorISR;
2145   }
2146   else if (hSemaphore == NULL) {
2147     stat = osErrorParameter;
2148   }
2149   else {
2150     #if (configQUEUE_REGISTRY_SIZE > 0)
2151     vQueueUnregisterQueue (hSemaphore);
2152     #endif
2153
2154     stat = osOK;
2155     vSemaphoreDelete (hSemaphore);
2156   }
2157 #else
2158   stat = osError;
2159 #endif
2160
2161   /* Return execution status */
2162   return (stat);
2163 }
2164
2165
2166 /* ==== Message Queue Management Functions ==== */
2167
2168 /*
2169   Create and Initialize a Message Queue object.
2170
2171   Limitations:
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.
2174 */
2175 osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr) {
2176   QueueHandle_t hQueue;
2177   int32_t mem;
2178
2179   hQueue = NULL;
2180
2181   if ((IRQ_Context() == 0U) && (msg_count > 0U) && (msg_size > 0U)) {
2182     mem = -1;
2183
2184     if (attr != NULL) {
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 */
2188         mem = 1;
2189       }
2190       else {
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 */
2194           mem = 0;
2195         }
2196       }
2197     }
2198     else {
2199       mem = 0;
2200     }
2201
2202     if (mem == 1) {
2203       #if (configSUPPORT_STATIC_ALLOCATION == 1)
2204         hQueue = xQueueCreateStatic (msg_count, msg_size, attr->mq_mem, attr->cb_mem);
2205       #endif
2206     }
2207     else {
2208       if (mem == 0) {
2209         #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
2210           hQueue = xQueueCreate (msg_count, msg_size);
2211         #endif
2212       }
2213     }
2214
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);
2220       }
2221     }
2222     #endif
2223
2224   }
2225
2226   /* Return message queue ID */
2227   return ((osMessageQueueId_t)hQueue);
2228 }
2229
2230 /*
2231   Put a Message into a Queue or timeout if Queue is full.
2232
2233   Limitations:
2234   - Message priority is ignored
2235 */
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;
2238   osStatus_t stat;
2239   BaseType_t yield;
2240
2241   (void)msg_prio; /* Message priority is ignored */
2242
2243   stat = osOK;
2244
2245   if (IRQ_Context() != 0U) {
2246     if ((hQueue == NULL) || (msg_ptr == NULL) || (timeout != 0U)) {
2247       stat = osErrorParameter;
2248     }
2249     else {
2250       yield = pdFALSE;
2251
2252       if (xQueueSendToBackFromISR (hQueue, msg_ptr, &yield) != pdTRUE) {
2253         stat = osErrorResource;
2254       } else {
2255         portYIELD_FROM_ISR (yield);
2256       }
2257     }
2258   }
2259   else {
2260     if ((hQueue == NULL) || (msg_ptr == NULL)) {
2261       stat = osErrorParameter;
2262     }
2263     else {
2264       if (xQueueSendToBack (hQueue, msg_ptr, (TickType_t)timeout) != pdPASS) {
2265         if (timeout != 0U) {
2266           stat = osErrorTimeout;
2267         } else {
2268           stat = osErrorResource;
2269         }
2270       }
2271     }
2272   }
2273
2274   /* Return execution status */
2275   return (stat);
2276 }
2277
2278 /*
2279   Get a Message from a Queue or timeout if Queue is empty.
2280
2281   Limitations:
2282   - Message priority is ignored
2283 */
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;
2286   osStatus_t stat;
2287   BaseType_t yield;
2288
2289   (void)msg_prio; /* Message priority is ignored */
2290
2291   stat = osOK;
2292
2293   if (IRQ_Context() != 0U) {
2294     if ((hQueue == NULL) || (msg_ptr == NULL) || (timeout != 0U)) {
2295       stat = osErrorParameter;
2296     }
2297     else {
2298       yield = pdFALSE;
2299
2300       if (xQueueReceiveFromISR (hQueue, msg_ptr, &yield) != pdPASS) {
2301         stat = osErrorResource;
2302       } else {
2303         portYIELD_FROM_ISR (yield);
2304       }
2305     }
2306   }
2307   else {
2308     if ((hQueue == NULL) || (msg_ptr == NULL)) {
2309       stat = osErrorParameter;
2310     }
2311     else {
2312       if (xQueueReceive (hQueue, msg_ptr, (TickType_t)timeout) != pdPASS) {
2313         if (timeout != 0U) {
2314           stat = osErrorTimeout;
2315         } else {
2316           stat = osErrorResource;
2317         }
2318       }
2319     }
2320   }
2321
2322   /* Return execution status */
2323   return (stat);
2324 }
2325
2326 /*
2327   Get maximum number of messages in a Message Queue.
2328 */
2329 uint32_t osMessageQueueGetCapacity (osMessageQueueId_t mq_id) {
2330   QueueHandle_t hQueue = (QueueHandle_t)mq_id;
2331   uint32_t capacity;
2332
2333   if (hQueue == NULL) {
2334     capacity = 0U;
2335   } else {
2336     capacity = uxQueueGetQueueLength (hQueue);
2337   }
2338
2339   /* Return maximum number of messages */
2340   return (capacity);
2341 }
2342
2343 /*
2344   Get maximum message size in a Message Queue.
2345 */
2346 uint32_t osMessageQueueGetMsgSize (osMessageQueueId_t mq_id) {
2347   QueueHandle_t hQueue = (QueueHandle_t)mq_id;
2348   uint32_t size;
2349
2350   if (hQueue == NULL) {
2351     size = 0U;
2352   } else {
2353     size = uxQueueGetQueueItemSize (hQueue);
2354   }
2355
2356   /* Return maximum message size */
2357   return (size);
2358 }
2359
2360 /*
2361   Get number of queued messages in a Message Queue.
2362 */
2363 uint32_t osMessageQueueGetCount (osMessageQueueId_t mq_id) {
2364   QueueHandle_t hQueue = (QueueHandle_t)mq_id;
2365   UBaseType_t count;
2366
2367   if (hQueue == NULL) {
2368     count = 0U;
2369   }
2370   else if (IRQ_Context() != 0U) {
2371     count = uxQueueMessagesWaitingFromISR (hQueue);
2372   }
2373   else {
2374     count = uxQueueMessagesWaiting (hQueue);
2375   }
2376
2377   /* Return number of queued messages */
2378   return ((uint32_t)count);
2379 }
2380
2381 /*
2382   Get number of available slots for messages in a Message Queue.
2383 */
2384 uint32_t osMessageQueueGetSpace (osMessageQueueId_t mq_id) {
2385   QueueHandle_t hQueue = (QueueHandle_t)mq_id;
2386   uint32_t space;
2387   uint32_t isrm;
2388
2389   if (hQueue == NULL) {
2390     space = 0U;
2391   }
2392   else if (IRQ_Context() != 0U) {
2393     isrm = taskENTER_CRITICAL_FROM_ISR();
2394
2395     space = uxQueueGetQueueLength (hQueue) - uxQueueMessagesWaiting (hQueue);
2396
2397     taskEXIT_CRITICAL_FROM_ISR(isrm);
2398   }
2399   else {
2400     space = (uint32_t)uxQueueSpacesAvailable (hQueue);
2401   }
2402
2403   /* Return number of available slots */
2404   return (space);
2405 }
2406
2407 /*
2408   Reset a Message Queue to initial empty state.
2409 */
2410 osStatus_t osMessageQueueReset (osMessageQueueId_t mq_id) {
2411   QueueHandle_t hQueue = (QueueHandle_t)mq_id;
2412   osStatus_t stat;
2413
2414   if (IRQ_Context() != 0U) {
2415     stat = osErrorISR;
2416   }
2417   else if (hQueue == NULL) {
2418     stat = osErrorParameter;
2419   }
2420   else {
2421     stat = osOK;
2422     (void)xQueueReset (hQueue);
2423   }
2424
2425   /* Return execution status */
2426   return (stat);
2427 }
2428
2429 /*
2430   Delete a Message Queue object.
2431 */
2432 osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id) {
2433   QueueHandle_t hQueue = (QueueHandle_t)mq_id;
2434   osStatus_t stat;
2435
2436 #ifndef USE_FreeRTOS_HEAP_1
2437   if (IRQ_Context() != 0U) {
2438     stat = osErrorISR;
2439   }
2440   else if (hQueue == NULL) {
2441     stat = osErrorParameter;
2442   }
2443   else {
2444     #if (configQUEUE_REGISTRY_SIZE > 0)
2445     vQueueUnregisterQueue (hQueue);
2446     #endif
2447
2448     stat = osOK;
2449     vQueueDelete (hQueue);
2450   }
2451 #else
2452   stat = osError;
2453 #endif
2454
2455   /* Return execution status */
2456   return (stat);
2457 }
2458
2459
2460 /* ==== Memory Pool Management Functions ==== */
2461
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);
2467
2468 /*
2469   Create and Initialize a Memory Pool object.
2470 */
2471 osMemoryPoolId_t osMemoryPoolNew (uint32_t block_count, uint32_t block_size, const osMemoryPoolAttr_t *attr) {
2472   MemPool_t *mp;
2473   const char *name;
2474   int32_t mem_cb, mem_mp;
2475   uint32_t sz;
2476
2477   if (IRQ_Context() != 0U) {
2478     mp = NULL;
2479   }
2480   else if ((block_count == 0U) || (block_size == 0U)) {
2481     mp = NULL;
2482   }
2483   else {
2484     mp = NULL;
2485     sz = MEMPOOL_ARR_SIZE (block_count, block_size);
2486
2487     name = NULL;
2488     mem_cb = -1;
2489     mem_mp = -1;
2490
2491     if (attr != NULL) {
2492       if (attr->name != NULL) {
2493         name = attr->name;
2494       }
2495
2496       if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(MemPool_t))) {
2497         /* Static control block is provided */
2498         mem_cb = 1;
2499       }
2500       else if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
2501         /* Allocate control block memory on heap */
2502         mem_cb = 0;
2503       }
2504
2505       if ((attr->mp_mem == NULL) && (attr->mp_size == 0U)) {
2506         /* Allocate memory array on heap */
2507           mem_mp = 0;
2508       }
2509       else {
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 */
2516               mem_mp = 1;
2517             }
2518           }
2519         }
2520       }
2521     }
2522     else {
2523       /* Attributes not provided, allocate memory on heap */
2524       mem_cb = 0;
2525       mem_mp = 0;
2526     }
2527
2528     if (mem_cb == 0) {
2529       mp = pvPortMalloc (sizeof(MemPool_t));
2530     } else {
2531       mp = attr->cb_mem;
2532     }
2533
2534     if (mp != NULL) {
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);
2540       #else
2541         mp->sem = NULL;
2542       #endif
2543
2544       if (mp->sem != NULL) {
2545         /* Setup memory array */
2546         if (mem_mp == 0) {
2547           mp->mem_arr = pvPortMalloc (sz);
2548         } else {
2549           mp->mem_arr = attr->mp_mem;
2550         }
2551       }
2552     }
2553
2554     if ((mp != NULL) && (mp->mem_arr != NULL)) {
2555       /* Memory pool can be created */
2556       mp->head    = NULL;
2557       mp->mem_sz  = sz;
2558       mp->name    = name;
2559       mp->bl_sz   = block_size;
2560       mp->bl_cnt  = block_count;
2561       mp->n       = 0U;
2562
2563       /* Set heap allocated memory flags */
2564       mp->status = MPOOL_STATUS;
2565
2566       if (mem_cb == 0) {
2567         /* Control block on heap */
2568         mp->status |= 1U;
2569       }
2570       if (mem_mp == 0) {
2571         /* Memory array on heap */
2572         mp->status |= 2U;
2573       }
2574     }
2575     else {
2576       /* Memory pool cannot be created, release allocated resources */
2577       if ((mem_cb == 0) && (mp != NULL)) {
2578         /* Free control block memory */
2579         vPortFree (mp);
2580       }
2581       mp = NULL;
2582     }
2583   }
2584
2585   /* Return memory pool ID */
2586   return (mp);
2587 }
2588
2589 /*
2590   Get name of a Memory Pool object.
2591 */
2592 const char *osMemoryPoolGetName (osMemoryPoolId_t mp_id) {
2593   MemPool_t *mp = (osMemoryPoolId_t)mp_id;
2594   const char *p;
2595
2596   if (mp_id == NULL) {
2597     p = NULL;
2598   }
2599   else if (IRQ_Context() != 0U) {
2600     p = mp->name;
2601   }
2602   else {
2603     p = mp->name;
2604   }
2605
2606   /* Return name as null-terminated string */
2607   return (p);
2608 }
2609
2610 /*
2611   Allocate a memory block from a Memory Pool.
2612 */
2613 void *osMemoryPoolAlloc (osMemoryPoolId_t mp_id, uint32_t timeout) {
2614   MemPool_t *mp;
2615   void *block;
2616   uint32_t isrm;
2617
2618   if (mp_id == NULL) {
2619     /* Invalid input parameters */
2620     block = NULL;
2621   }
2622   else {
2623     block = NULL;
2624
2625     mp = (MemPool_t *)mp_id;
2626
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();
2633
2634               /* Get a block from the free-list */
2635               block = AllocBlock(mp);
2636
2637               if (block == NULL) {
2638                 /* List of free blocks is empty, 'create' new block */
2639                 block = CreateBlock(mp);
2640               }
2641
2642               taskEXIT_CRITICAL_FROM_ISR(isrm);
2643             }
2644           }
2645         }
2646       }
2647       else {
2648         if (xSemaphoreTake (mp->sem, (TickType_t)timeout) == pdTRUE) {
2649           if ((mp->status & MPOOL_STATUS) == MPOOL_STATUS) {
2650             taskENTER_CRITICAL();
2651
2652             /* Get a block from the free-list */
2653             block = AllocBlock(mp);
2654
2655             if (block == NULL) {
2656               /* List of free blocks is empty, 'create' new block */
2657               block = CreateBlock(mp);
2658             }
2659
2660             taskEXIT_CRITICAL();
2661           }
2662         }
2663       }
2664     }
2665   }
2666
2667   /* Return memory block address */
2668   return (block);
2669 }
2670
2671 /*
2672   Return an allocated memory block back to a Memory Pool.
2673 */
2674 osStatus_t osMemoryPoolFree (osMemoryPoolId_t mp_id, void *block) {
2675   MemPool_t *mp;
2676   osStatus_t stat;
2677   uint32_t isrm;
2678   BaseType_t yield;
2679
2680   if ((mp_id == NULL) || (block == NULL)) {
2681     /* Invalid input parameters */
2682     stat = osErrorParameter;
2683   }
2684   else {
2685     mp = (MemPool_t *)mp_id;
2686
2687     if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) {
2688       /* Invalid object status */
2689       stat = osErrorResource;
2690     }
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;
2694     }
2695     else {
2696       stat = osOK;
2697
2698       if (IRQ_Context() != 0U) {
2699         if (uxSemaphoreGetCountFromISR (mp->sem) == mp->bl_cnt) {
2700           stat = osErrorResource;
2701         }
2702         else {
2703           isrm = taskENTER_CRITICAL_FROM_ISR();
2704
2705           /* Add block to the list of free blocks */
2706           FreeBlock(mp, block);
2707
2708           taskEXIT_CRITICAL_FROM_ISR(isrm);
2709
2710           yield = pdFALSE;
2711           xSemaphoreGiveFromISR (mp->sem, &yield);
2712           portYIELD_FROM_ISR (yield);
2713         }
2714       }
2715       else {
2716         if (uxSemaphoreGetCount (mp->sem) == mp->bl_cnt) {
2717           stat = osErrorResource;
2718         }
2719         else {
2720           taskENTER_CRITICAL();
2721
2722           /* Add block to the list of free blocks */
2723           FreeBlock(mp, block);
2724
2725           taskEXIT_CRITICAL();
2726
2727           xSemaphoreGive (mp->sem);
2728         }
2729       }
2730     }
2731   }
2732
2733   /* Return execution status */
2734   return (stat);
2735 }
2736
2737 /*
2738   Get maximum number of memory blocks in a Memory Pool.
2739 */
2740 uint32_t osMemoryPoolGetCapacity (osMemoryPoolId_t mp_id) {
2741   MemPool_t *mp;
2742   uint32_t  n;
2743
2744   if (mp_id == NULL) {
2745     /* Invalid input parameters */
2746     n = 0U;
2747   }
2748   else {
2749     mp = (MemPool_t *)mp_id;
2750
2751     if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) {
2752       /* Invalid object status */
2753       n = 0U;
2754     }
2755     else {
2756       n = mp->bl_cnt;
2757     }
2758   }
2759
2760   /* Return maximum number of memory blocks */
2761   return (n);
2762 }
2763
2764 /*
2765   Get memory block size in a Memory Pool.
2766 */
2767 uint32_t osMemoryPoolGetBlockSize (osMemoryPoolId_t mp_id) {
2768   MemPool_t *mp;
2769   uint32_t  sz;
2770
2771   if (mp_id == NULL) {
2772     /* Invalid input parameters */
2773     sz = 0U;
2774   }
2775   else {
2776     mp = (MemPool_t *)mp_id;
2777
2778     if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) {
2779       /* Invalid object status */
2780       sz = 0U;
2781     }
2782     else {
2783       sz = mp->bl_sz;
2784     }
2785   }
2786
2787   /* Return memory block size in bytes */
2788   return (sz);
2789 }
2790
2791 /*
2792   Get number of memory blocks used in a Memory Pool.
2793 */
2794 uint32_t osMemoryPoolGetCount (osMemoryPoolId_t mp_id) {
2795   MemPool_t *mp;
2796   uint32_t  n;
2797
2798   if (mp_id == NULL) {
2799     /* Invalid input parameters */
2800     n = 0U;
2801   }
2802   else {
2803     mp = (MemPool_t *)mp_id;
2804
2805     if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) {
2806       /* Invalid object status */
2807       n = 0U;
2808     }
2809     else {
2810       if (IRQ_Context() != 0U) {
2811         n = uxSemaphoreGetCountFromISR (mp->sem);
2812       } else {
2813         n = uxSemaphoreGetCount        (mp->sem);
2814       }
2815
2816       n = mp->bl_cnt - n;
2817     }
2818   }
2819
2820   /* Return number of memory blocks used */
2821   return (n);
2822 }
2823
2824 /*
2825   Get number of memory blocks available in a Memory Pool.
2826 */
2827 uint32_t osMemoryPoolGetSpace (osMemoryPoolId_t mp_id) {
2828   MemPool_t *mp;
2829   uint32_t  n;
2830
2831   if (mp_id == NULL) {
2832     /* Invalid input parameters */
2833     n = 0U;
2834   }
2835   else {
2836     mp = (MemPool_t *)mp_id;
2837
2838     if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) {
2839       /* Invalid object status */
2840       n = 0U;
2841     }
2842     else {
2843       if (IRQ_Context() != 0U) {
2844         n = uxSemaphoreGetCountFromISR (mp->sem);
2845       } else {
2846         n = uxSemaphoreGetCount        (mp->sem);
2847       }
2848     }
2849   }
2850
2851   /* Return number of memory blocks available */
2852   return (n);
2853 }
2854
2855 /*
2856   Delete a Memory Pool object.
2857 */
2858 osStatus_t osMemoryPoolDelete (osMemoryPoolId_t mp_id) {
2859   MemPool_t *mp;
2860   osStatus_t stat;
2861
2862   if (mp_id == NULL) {
2863     /* Invalid input parameters */
2864     stat = osErrorParameter;
2865   }
2866   else if (IRQ_Context() != 0U) {
2867     stat = osErrorISR;
2868   }
2869   else {
2870     mp = (MemPool_t *)mp_id;
2871
2872     taskENTER_CRITICAL();
2873
2874     /* Invalidate control block status */
2875     mp->status  = mp->status & 3U;
2876
2877     /* Wake-up tasks waiting for pool semaphore */
2878     while (xSemaphoreGive (mp->sem) == pdTRUE);
2879
2880     mp->head    = NULL;
2881     mp->bl_sz   = 0U;
2882     mp->bl_cnt  = 0U;
2883
2884     if ((mp->status & 2U) != 0U) {
2885       /* Memory pool array allocated on heap */
2886       vPortFree (mp->mem_arr);
2887     }
2888     if ((mp->status & 1U) != 0U) {
2889       /* Memory pool control block allocated on heap */
2890       vPortFree (mp);
2891     }
2892
2893     taskEXIT_CRITICAL();
2894
2895     stat = osOK;
2896   }
2897
2898   /* Return execution status */
2899   return (stat);
2900 }
2901
2902 /*
2903   Create new block given according to the current block index.
2904 */
2905 static void *CreateBlock (MemPool_t *mp) {
2906   MemPoolBlock_t *p = NULL;
2907
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));
2911
2912     /* Increment block index */
2913     mp->n += 1U;
2914   }
2915
2916   return (p);
2917 }
2918
2919 /*
2920   Allocate a block by reading the list of free blocks.
2921 */
2922 static void *AllocBlock (MemPool_t *mp) {
2923   MemPoolBlock_t *p = NULL;
2924
2925   if (mp->head != NULL) {
2926     /* List of free block exists, get head block */
2927     p = mp->head;
2928
2929     /* Head block is now next on the list */
2930     mp->head = p->next;
2931   }
2932
2933   return (p);
2934 }
2935
2936 /*
2937   Free block by putting it to the list of free blocks.
2938 */
2939 static void FreeBlock (MemPool_t *mp, void *block) {
2940   MemPoolBlock_t *p = block;
2941
2942   /* Store current head into block memory space */
2943   p->next = mp->head;
2944
2945   /* Store current block as new head */
2946   mp->head = p;
2947 }
2948 #endif /* FREERTOS_MPOOL_H_ */
2949 /*---------------------------------------------------------------------------*/
2950
2951 /* Callback function prototypes */
2952 extern void vApplicationIdleHook (void);
2953 extern void vApplicationMallocFailedHook (void);
2954 extern void vApplicationDaemonTaskStartupHook (void);
2955
2956 /**
2957   Dummy implementation of the callback function vApplicationIdleHook().
2958 */
2959 #if (configUSE_IDLE_HOOK == 1)
2960 __WEAK void vApplicationIdleHook (void){}
2961 #endif
2962
2963 /**
2964   Dummy implementation of the callback function vApplicationTickHook().
2965 */
2966 #if (configUSE_TICK_HOOK == 1)
2967  __WEAK void vApplicationTickHook (void){}
2968 #endif
2969
2970 /**
2971   Dummy implementation of the callback function vApplicationMallocFailedHook().
2972 */
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 */
2976   configASSERT(0);
2977 }
2978 #endif
2979
2980 /**
2981   Dummy implementation of the callback function vApplicationDaemonTaskStartupHook().
2982 */
2983 #if (configUSE_DAEMON_TASK_STARTUP_HOOK == 1)
2984 __WEAK void vApplicationDaemonTaskStartupHook (void){}
2985 #endif
2986
2987 /**
2988   Dummy implementation of the callback function vApplicationStackOverflowHook().
2989 */
2990 #if (configCHECK_FOR_STACK_OVERFLOW > 0)
2991 __WEAK void vApplicationStackOverflowHook (TaskHandle_t xTask, char *pcTaskName) {
2992   (void)xTask;
2993   (void)pcTaskName;
2994
2995   /* Assert when stack overflow is enabled but no application defined function exists */
2996   configASSERT(0);
2997 }
2998 #endif