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