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