Просмотр исходного кода

[FL-1910, FL-2146] Update to new FreeRTOS, fix CMSIS thread flags collision with stream buffer. New cube. (#917)

* Libs: add FreeRTOS submodule. FuriHal: replace ST provided FreeRTOS with original one. FuriHal: for cmsis os hal and patch it for better compatibility with stream buffer.
* Makefile: fix svd plugin on blackmagic
* Lib: update STM32CubeWB package. Project: update project to match new cube package.
* Lib: properly rebase and upload STM32CubeWB
* BleGlue: switch ack logging level to trace
あく 4 лет назад
Родитель
Сommit
439fb9c18d
39 измененных файлов с 4317 добавлено и 358 удалено
  1. 3 0
      .gitmodules
  2. 1 1
      Makefile
  3. 1 1
      applications/debug_tools/usb_test.c
  4. 3 2
      applications/rpc/rpc.c
  5. 2 1
      applications/rpc/rpc.h
  6. 1 1
      applications/subghz/views/subghz_test_carrier.c
  7. 2 2
      applications/subghz/views/subghz_test_packet.c
  8. 74 127
      firmware/targets/f6/Inc/FreeRTOSConfig.h
  9. 0 21
      firmware/targets/f6/Src/freertos-openocd.c
  10. 0 1
      firmware/targets/f6/ble-glue/ble_app.c
  11. 0 1
      firmware/targets/f6/ble-glue/ble_glue.c
  12. 2 3
      firmware/targets/f6/ble-glue/gap.c
  13. 1 1
      firmware/targets/f6/ble-glue/serial_service.c
  14. 0 1
      firmware/targets/f6/fatfs/ffconf.h
  15. 2 2
      firmware/targets/f6/furi-hal/furi-hal-os.c
  16. 0 1
      firmware/targets/f6/furi-hal/furi-hal-task.c
  17. 12 11
      firmware/targets/f6/target.mk
  18. 74 127
      firmware/targets/f7/Inc/FreeRTOSConfig.h
  19. 0 21
      firmware/targets/f7/Src/freertos-openocd.c
  20. 0 1
      firmware/targets/f7/ble-glue/ble_app.c
  21. 0 1
      firmware/targets/f7/ble-glue/ble_glue.c
  22. 2 3
      firmware/targets/f7/ble-glue/gap.c
  23. 1 1
      firmware/targets/f7/ble-glue/serial_service.c
  24. 0 1
      firmware/targets/f7/fatfs/ffconf.h
  25. 2 2
      firmware/targets/f7/furi-hal/furi-hal-os.c
  26. 0 1
      firmware/targets/f7/furi-hal/furi-hal-task.c
  27. 12 11
      firmware/targets/f7/target.mk
  28. 1 0
      lib/FreeRTOS-Kernel
  29. 2873 0
      lib/FreeRTOS-glue/cmsis_os2.c
  30. 756 0
      lib/FreeRTOS-glue/cmsis_os2.h
  31. 63 0
      lib/FreeRTOS-glue/freertos_mpool.h
  32. 336 0
      lib/FreeRTOS-glue/freertos_os2.h
  33. 80 0
      lib/FreeRTOS-glue/os_tick.h
  34. 1 1
      lib/ST25RFAL002/platform.c
  35. 1 1
      lib/STM32CubeWB
  36. 2 2
      lib/lib.mk
  37. 2 1
      make/rules.mk
  38. 5 5
      scripts/flipper/copro.py
  39. 2 2
      scripts/ob.data

+ 3 - 0
.gitmodules

@@ -16,3 +16,6 @@
 [submodule "lib/libusb_stm32"]
 	path = lib/libusb_stm32
 	url = https://github.com/flipperdevices/libusb_stm32.git
+[submodule "lib/FreeRTOS-Kernel"]
+	path = lib/FreeRTOS-Kernel
+	url = https://github.com/FreeRTOS/FreeRTOS-Kernel.git

+ 1 - 1
Makefile

@@ -71,7 +71,7 @@ endif
 
 .PHONY: flash_radio
 flash_radio:
-	@$(PROJECT_ROOT)/scripts/flash.py core2radio 0x080CA000 $(COPRO_DIR)/stm32wb5x_BLE_Stack_full_fw.bin
+	@$(PROJECT_ROOT)/scripts/flash.py core2radio 0x080C7000 $(COPRO_DIR)/stm32wb5x_BLE_Stack_full_fw.bin
 	@$(PROJECT_ROOT)/scripts/ob.py set
 
 .PHONY: flash_radio_fus

+ 1 - 1
applications/debug_tools/usb_test.c

@@ -1,10 +1,10 @@
 #include <furi.h>
 #include <furi-hal.h>
+
 #include <gui/view.h>
 #include <gui/view_dispatcher.h>
 #include <gui/modules/submenu.h>
 #include <gui/gui.h>
-#include <cmsis_os.h>
 
 typedef struct {
     Gui* gui;

+ 3 - 2
applications/rpc/rpc.c

@@ -1,13 +1,14 @@
 #include "rpc_i.h"
+
 #include <pb.h>
 #include <pb_decode.h>
 #include <pb_encode.h>
+
 #include <status.pb.h>
 #include <storage.pb.h>
 #include <flipper.pb.h>
-#include <cmsis_os.h>
-#include <cmsis_os2.h>
 #include <portmacro.h>
+
 #include <furi.h>
 
 #include <cli/cli.h>

+ 2 - 1
applications/rpc/rpc.h

@@ -1,8 +1,9 @@
 #pragma once
+
 #include <stddef.h>
 #include <stdint.h>
 #include <stdbool.h>
-#include "cmsis_os.h"
+#include <furi.h>
 
 #define RPC_BUFFER_SIZE (1024)
 #define RPC_MAX_MESSAGE_SIZE (1536)

+ 1 - 1
applications/subghz/views/subghz_test_carrier.c

@@ -8,7 +8,7 @@
 
 struct SubghzTestCarrier {
     View* view;
-    osTimerId timer;
+    osTimerId_t timer;
     SubghzTestCarrierCallback callback;
     void* context;
 };

+ 2 - 2
applications/subghz/views/subghz_test_packet.c

@@ -12,7 +12,7 @@
 
 struct SubghzTestPacket {
     View* view;
-    osTimerId timer;
+    osTimerId_t timer;
 
     SubGhzDecoderPrinceton* decoder;
     SubGhzEncoderPrinceton* encoder;
@@ -262,4 +262,4 @@ void subghz_test_packet_free(SubghzTestPacket* instance) {
 View* subghz_test_packet_get_view(SubghzTestPacket* instance) {
     furi_assert(instance);
     return instance->view;
-}
+}

+ 74 - 127
firmware/targets/f6/Inc/FreeRTOSConfig.h

@@ -1,133 +1,89 @@
-/* USER CODE BEGIN Header */
-/*
- * FreeRTOS Kernel V10.2.1
- * Portion Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
- * Portion Copyright (C) 2019 StMicroelectronics, Inc.  All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * http://www.FreeRTOS.org
- * http://aws.amazon.com/freertos
- *
- * 1 tab == 4 spaces!
- */
-/* USER CODE END Header */
-
-#ifndef FREERTOS_CONFIG_H
-#define FREERTOS_CONFIG_H
-
-/*-----------------------------------------------------------
- * Application specific definitions.
- *
- * These definitions should be adjusted for your particular hardware and
- * application requirements.
- *
- * These parameters and more are described within the 'configuration' section of the
- * FreeRTOS API documentation available on the FreeRTOS.org web site.
- *
- * See http://www.freertos.org/a00110.html
- *----------------------------------------------------------*/
-
-/* USER CODE BEGIN Includes */
-/* Section where include file can be added */
-/* USER CODE END Includes */
-
-/* Ensure definitions are only used by the compiler, and not by the assembler. */
+#pragma once
+
 #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
-  #include <stdint.h>
-  extern uint32_t SystemCoreClock;
+#include <stdint.h>
+extern uint32_t SystemCoreClock;
 #endif
+
 #ifndef CMSIS_device_header
 #define CMSIS_device_header "stm32wbxx.h"
 #endif /* CMSIS_device_header */
 
-#define configENABLE_FPU                         1
-#define configENABLE_MPU                         0
-
-#define configUSE_PREEMPTION                     1
-#define configSUPPORT_STATIC_ALLOCATION          0
-#define configSUPPORT_DYNAMIC_ALLOCATION         1
-#define configUSE_IDLE_HOOK                      0
-#define configUSE_TICK_HOOK                      0
-#define configCPU_CLOCK_HZ                       ( SystemCoreClock )
-#define configTICK_RATE_HZ                       ((TickType_t)1024)
-#define configMAX_PRIORITIES                     ( 56 )
-#define configMINIMAL_STACK_SIZE                 ((uint16_t)128)
+#define configENABLE_FPU                            1
+#define configENABLE_MPU                            0
+
+#define configUSE_PREEMPTION                        1
+#define configSUPPORT_STATIC_ALLOCATION             0
+#define configSUPPORT_DYNAMIC_ALLOCATION            1
+#define configUSE_IDLE_HOOK                         0
+#define configUSE_TICK_HOOK                         0
+#define configCPU_CLOCK_HZ                          ( SystemCoreClock )
+#define configTICK_RATE_HZ                          ((TickType_t)1024)
+#define configMAX_PRIORITIES                        ( 56 )
+#define configMINIMAL_STACK_SIZE                    ((uint16_t)128)
+
 /* Heap size determined automatically by linker */
 // #define configTOTAL_HEAP_SIZE                    ((size_t)0)
-#define configMAX_TASK_NAME_LEN                  ( 16 )
-#define configGENERATE_RUN_TIME_STATS            0
-#define configUSE_TRACE_FACILITY                 1
-#define configUSE_16_BIT_TICKS                   0
-#define configUSE_MUTEXES                        1
-#define configQUEUE_REGISTRY_SIZE                8
-#define configCHECK_FOR_STACK_OVERFLOW           1
-#define configUSE_RECURSIVE_MUTEXES              1
-#define configUSE_COUNTING_SEMAPHORES            1
-#define configENABLE_BACKWARD_COMPATIBILITY      0
-#define configUSE_PORT_OPTIMISED_TASK_SELECTION  0
-#define configUSE_TICKLESS_IDLE                  2
-#define configRECORD_STACK_HIGH_ADDRESS          1
-#define configUSE_NEWLIB_REENTRANT               0
-/* USER CODE BEGIN MESSAGE_BUFFER_LENGTH_TYPE */
+#define configMAX_TASK_NAME_LEN                     ( 16 )
+#define configGENERATE_RUN_TIME_STATS               0
+#define configUSE_TRACE_FACILITY                    1
+#define configUSE_16_BIT_TICKS                      0
+#define configUSE_MUTEXES                           1
+#define configQUEUE_REGISTRY_SIZE                   8
+#define configCHECK_FOR_STACK_OVERFLOW              1
+#define configUSE_RECURSIVE_MUTEXES                 1
+#define configUSE_COUNTING_SEMAPHORES               1
+#define configENABLE_BACKWARD_COMPATIBILITY         0
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION     0
+#define configUSE_TICKLESS_IDLE                     2
+#define configRECORD_STACK_HIGH_ADDRESS             1
+#define configUSE_NEWLIB_REENTRANT                  0
+
 /* Defaults to size_t for backward compatibility, but can be changed
    if lengths will always be less than the number of bytes in a size_t. */
-#define configMESSAGE_BUFFER_LENGTH_TYPE         size_t
-#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 1
-#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP   8
-/* USER CODE END MESSAGE_BUFFER_LENGTH_TYPE */
+#define configMESSAGE_BUFFER_LENGTH_TYPE            size_t
+#define configNUM_THREAD_LOCAL_STORAGE_POINTERS     1
+#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP       4
 
 /* Co-routine definitions. */
-#define configUSE_CO_ROUTINES                    0
-#define configMAX_CO_ROUTINE_PRIORITIES          ( 2 )
+#define configUSE_CO_ROUTINES                       0
 
 /* Software timer definitions. */
-#define configUSE_TIMERS                         1
-#define configTIMER_TASK_PRIORITY                ( 2 )
-#define configTIMER_QUEUE_LENGTH                 32
-#define configTIMER_TASK_STACK_DEPTH             256
-#define configTIMER_SERVICE_TASK_NAME          "TimersSrv"
+#define configUSE_TIMERS                            1
+#define configTIMER_TASK_PRIORITY                   ( 2 )
+#define configTIMER_QUEUE_LENGTH                    32
+#define configTIMER_TASK_STACK_DEPTH                256
+#define configTIMER_SERVICE_TASK_NAME               "TimersSrv"
 
-#define configIDLE_TASK_NAME                  "(-_-)"
+#define configIDLE_TASK_NAME                        "(-_-)"
 
 /* Set the following definitions to 1 to include the API function, or zero
 to exclude the API function. */
-#define INCLUDE_eTaskGetState                1
-#define INCLUDE_uxTaskGetStackHighWaterMark  1
-#define INCLUDE_uxTaskPriorityGet            1
-#define INCLUDE_vTaskCleanUpResources        0
-#define INCLUDE_vTaskDelay                   1
-#define INCLUDE_vTaskDelayUntil              1
-#define INCLUDE_vTaskDelete                  1
-#define INCLUDE_vTaskPrioritySet             1
-#define INCLUDE_vTaskSuspend                 1
-#define INCLUDE_xQueueGetMutexHolder         1
-#define INCLUDE_xTaskGetCurrentTaskHandle    1
-#define INCLUDE_xTaskGetSchedulerState       1
-#define INCLUDE_xTimerPendFunctionCall       1
+#define INCLUDE_eTaskGetState                       1
+#define INCLUDE_uxTaskGetStackHighWaterMark         1
+#define INCLUDE_uxTaskPriorityGet                   1
+#define INCLUDE_vTaskCleanUpResources               0
+#define INCLUDE_vTaskDelay                          1
+#define INCLUDE_vTaskDelayUntil                     1
+#define INCLUDE_vTaskDelete                         1
+#define INCLUDE_vTaskPrioritySet                    1
+#define INCLUDE_vTaskSuspend                        1
+#define INCLUDE_xQueueGetMutexHolder                1
+#define INCLUDE_xTaskGetCurrentTaskHandle           1
+#define INCLUDE_xTaskGetSchedulerState              1
+#define INCLUDE_xTimerPendFunctionCall              1
 
 /* CMSIS-RTOS V2 flags */
-#define configUSE_OS2_THREAD_SUSPEND_RESUME  1
-#define configUSE_OS2_THREAD_ENUMERATE       1
-#define configUSE_OS2_EVENTFLAGS_FROM_ISR    1
-#define configUSE_OS2_THREAD_FLAGS           1
-#define configUSE_OS2_TIMER                  1
-#define configUSE_OS2_MUTEX                  1
+#define configUSE_OS2_THREAD_SUSPEND_RESUME         1
+#define configUSE_OS2_THREAD_ENUMERATE              1
+#define configUSE_OS2_EVENTFLAGS_FROM_ISR           1
+#define configUSE_OS2_THREAD_FLAGS                  1
+#define configUSE_OS2_TIMER                         1
+#define configUSE_OS2_MUTEX                         1
+
+/* CMSIS-RTOS */
+#define configTASK_NOTIFICATION_ARRAY_ENTRIES       2
+#define CMSIS_TASK_NOTIFY_INDEX 1
 
 /*
  * The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used
@@ -137,15 +93,15 @@ to exclude the API function. */
 
 /* Cortex-M specific definitions. */
 #ifdef __NVIC_PRIO_BITS
- /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
- #define configPRIO_BITS         __NVIC_PRIO_BITS
+    /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
+    #define configPRIO_BITS                         __NVIC_PRIO_BITS
 #else
- #define configPRIO_BITS         4
+    #define configPRIO_BITS                         4
 #endif
 
 /* The lowest interrupt priority that can be used in a call to a "set priority"
 function. */
-#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   15
+#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY     15
 
 /* The highest interrupt priority that can be used by any interrupt service
 routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
@@ -155,29 +111,20 @@ PRIORITY THAN THIS! (higher priorities are lower numeric values. */
 
 /* Interrupt priorities used by the kernel port layer itself.  These are generic
 to all Cortex-M ports, and do not rely on any particular library functions. */
-#define configKERNEL_INTERRUPT_PRIORITY         ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
+#define configKERNEL_INTERRUPT_PRIORITY             ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
+
 /* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
 See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
-#define configMAX_SYSCALL_INTERRUPT_PRIORITY    ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
+#define configMAX_SYSCALL_INTERRUPT_PRIORITY        ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
 
 /* Normal assert() semantics without relying on the provision of an assert.h
 header file. */
-/* USER CODE BEGIN 1 */
-#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); asm("bkpt 1"); for( ;; );}
-/* USER CODE END 1 */
+#define configASSERT( x ) if ((x) == 0) { taskDISABLE_INTERRUPTS(); asm("bkpt 1"); for( ;; ); }
 
 /* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
 standard names. */
 #define vPortSVCHandler    SVC_Handler
 #define xPortPendSVHandler PendSV_Handler
 
-/* IMPORTANT: After 10.3.1 update, Systick_Handler comes from NVIC (if SYS timebase = systick), otherwise from cmsis_os2.c */
-
 #define USE_CUSTOM_SYSTICK_HANDLER_IMPLEMENTATION 1
-
-/* USER CODE BEGIN Defines */
-/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */
 #define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 1  /* required only for Keil but does not hurt otherwise */
-/* USER CODE END Defines */
-
-#endif /* FREERTOS_CONFIG_H */

+ 0 - 21
firmware/targets/f6/Src/freertos-openocd.c

@@ -1,21 +0,0 @@
-
-/*
- * Since at least FreeRTOS V7.5.3 uxTopUsedPriority is no longer
- * present in the kernel, so it has to be supplied by other means for
- * OpenOCD's threads awareness.
- *
- * Add this file to your project, and, if you're using --gc-sections,
- * ``--undefined=uxTopUsedPriority'' (or
- * ``-Wl,--undefined=uxTopUsedPriority'' when using gcc for final
- * linking) to your LDFLAGS; same with all the other symbols you need.
- */
-
-#include "FreeRTOS.h"
-
-#ifdef __GNUC__
-#define USED __attribute__((used))
-#else
-#define USED
-#endif
-
-const int USED uxTopUsedPriority = configMAX_PRIORITIES - 1;

+ 0 - 1
firmware/targets/f6/ble-glue/ble_app.c

@@ -3,7 +3,6 @@
 #include "hci_tl.h"
 #include "ble.h"
 #include "shci.h"
-#include "cmsis_os.h"
 #include "gap.h"
 
 #include <furi-hal.h>

+ 0 - 1
firmware/targets/f6/ble-glue/ble_glue.c

@@ -5,7 +5,6 @@
 #include "ble.h"
 #include "tl.h"
 #include "shci.h"
-#include "cmsis_os.h"
 #include "shci_tl.h"
 #include "app_debug.h"
 #include <furi-hal.h>

+ 2 - 3
firmware/targets/f6/ble-glue/gap.c

@@ -2,7 +2,6 @@
 
 #include "ble.h"
 
-#include "cmsis_os.h"
 #include <furi-hal.h>
 #include <furi.h>
 
@@ -28,7 +27,7 @@ typedef struct {
     osMutexId_t state_mutex;
     BleEventCallback on_event_cb;
     void* context;
-    osTimerId advertise_timer;
+    osTimerId_t advertise_timer;
     FuriThread* thread;
     osMessageQueueId_t command_queue;
     bool enable_adv;
@@ -446,7 +445,7 @@ void gap_thread_stop() {
 static int32_t gap_app(void *context) {
     GapCommand command;
     while(1) {
-        osStatus status = osMessageQueueGet(gap->command_queue, &command, NULL, osWaitForever);
+        osStatus_t status = osMessageQueueGet(gap->command_queue, &command, NULL, osWaitForever);
         if(status != osOK) {
             FURI_LOG_E(TAG, "Message queue get error: %d", status);
             continue;

+ 1 - 1
firmware/targets/f6/ble-glue/serial_service.c

@@ -62,7 +62,7 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void *event) {
                 ret = SVCCTL_EvtAckFlowEnable;
             }
         } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) {
-            FURI_LOG_D(TAG, "Ack received", blecore_evt->ecode);
+            FURI_LOG_T(TAG, "Ack received", blecore_evt->ecode);
             if(serial_svc->callback) {
                 SerialServiceEvent event = {
                     .event = SerialServiceEventTypeDataSent,

+ 0 - 1
firmware/targets/f6/fatfs/ffconf.h

@@ -26,7 +26,6 @@
 
 #include "main.h"
 #include "stm32wbxx_hal.h"
-#include "cmsis_os.h" /* _FS_REENTRANT set to 1 and CMSIS API chosen */
 
 /*-----------------------------------------------------------------------------/
 / Function Configurations

+ 2 - 2
firmware/targets/f6/furi-hal/furi-hal-os.c

@@ -43,7 +43,7 @@ void furi_hal_os_init() {
     LL_GPIO_SetPinMode(LED_TICK_PORT, LED_TICK_PIN, LL_GPIO_MODE_OUTPUT);
     LL_GPIO_SetPinMode(LED_SECOND_PORT, LED_SECOND_PIN, LL_GPIO_MODE_OUTPUT);
     osTimerId_t second_timer = osTimerNew(furi_hal_os_timer_callback, osTimerPeriodic, NULL, NULL);
-    osTimerStart(second_timer, 1024);
+    osTimerStart(second_timer, FURI_HAL_OS_TICK_PER_SECOND);
 #endif
 
     FURI_LOG_I(TAG, "Init OK");
@@ -139,7 +139,7 @@ void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) {
     __enable_irq();
 }
 
-void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName) {
+void vApplicationStackOverflowHook(TaskHandle_t xTask, char * pcTaskName) {
     asm("bkpt 1");
     while(1) {};
 }

+ 0 - 1
firmware/targets/f6/furi-hal/furi-hal-task.c

@@ -1,4 +1,3 @@
-#include "cmsis_os.h"
 #include "furi-hal-task.h"
 
 //-----------------------------cmsis_os2.c-------------------------------

+ 12 - 11
firmware/targets/f6/target.mk

@@ -75,18 +75,19 @@ C_SOURCES += \
 
 # FreeRTOS
 CFLAGS += \
-	-I$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/include \
-	-I$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 \
-	-I$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F
+	-I$(LIB_DIR)/FreeRTOS-Kernel/include \
+	-I$(LIB_DIR)/FreeRTOS-Kernel/portable/GCC/ARM_CM4F \
+	-I$(LIB_DIR)/FreeRTOS-glue/
+
 C_SOURCES += \
-	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \
-	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/list.c \
-	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/queue.c \
-	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c \
-	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/tasks.c \
-	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/timers.c \
-	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c \
-	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c
+	$(LIB_DIR)/FreeRTOS-Kernel/event_groups.c \
+	$(LIB_DIR)/FreeRTOS-Kernel/list.c \
+	$(LIB_DIR)/FreeRTOS-Kernel/queue.c \
+	$(LIB_DIR)/FreeRTOS-Kernel/stream_buffer.c \
+	$(LIB_DIR)/FreeRTOS-Kernel/tasks.c \
+	$(LIB_DIR)/FreeRTOS-Kernel/timers.c \
+	$(LIB_DIR)/FreeRTOS-Kernel/portable/GCC/ARM_CM4F/port.c \
+	$(LIB_DIR)/FreeRTOS-glue/cmsis_os2.c \
 
 # BLE glue 
 CFLAGS += \

+ 74 - 127
firmware/targets/f7/Inc/FreeRTOSConfig.h

@@ -1,133 +1,89 @@
-/* USER CODE BEGIN Header */
-/*
- * FreeRTOS Kernel V10.2.1
- * Portion Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
- * Portion Copyright (C) 2019 StMicroelectronics, Inc.  All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * http://www.FreeRTOS.org
- * http://aws.amazon.com/freertos
- *
- * 1 tab == 4 spaces!
- */
-/* USER CODE END Header */
-
-#ifndef FREERTOS_CONFIG_H
-#define FREERTOS_CONFIG_H
-
-/*-----------------------------------------------------------
- * Application specific definitions.
- *
- * These definitions should be adjusted for your particular hardware and
- * application requirements.
- *
- * These parameters and more are described within the 'configuration' section of the
- * FreeRTOS API documentation available on the FreeRTOS.org web site.
- *
- * See http://www.freertos.org/a00110.html
- *----------------------------------------------------------*/
-
-/* USER CODE BEGIN Includes */
-/* Section where include file can be added */
-/* USER CODE END Includes */
-
-/* Ensure definitions are only used by the compiler, and not by the assembler. */
+#pragma once
+
 #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
-  #include <stdint.h>
-  extern uint32_t SystemCoreClock;
+#include <stdint.h>
+extern uint32_t SystemCoreClock;
 #endif
+
 #ifndef CMSIS_device_header
 #define CMSIS_device_header "stm32wbxx.h"
 #endif /* CMSIS_device_header */
 
-#define configENABLE_FPU                         1
-#define configENABLE_MPU                         0
-
-#define configUSE_PREEMPTION                     1
-#define configSUPPORT_STATIC_ALLOCATION          0
-#define configSUPPORT_DYNAMIC_ALLOCATION         1
-#define configUSE_IDLE_HOOK                      0
-#define configUSE_TICK_HOOK                      0
-#define configCPU_CLOCK_HZ                       ( SystemCoreClock )
-#define configTICK_RATE_HZ                       ((TickType_t)1024)
-#define configMAX_PRIORITIES                     ( 56 )
-#define configMINIMAL_STACK_SIZE                 ((uint16_t)128)
+#define configENABLE_FPU                            1
+#define configENABLE_MPU                            0
+
+#define configUSE_PREEMPTION                        1
+#define configSUPPORT_STATIC_ALLOCATION             0
+#define configSUPPORT_DYNAMIC_ALLOCATION            1
+#define configUSE_IDLE_HOOK                         0
+#define configUSE_TICK_HOOK                         0
+#define configCPU_CLOCK_HZ                          ( SystemCoreClock )
+#define configTICK_RATE_HZ                          ((TickType_t)1024)
+#define configMAX_PRIORITIES                        ( 56 )
+#define configMINIMAL_STACK_SIZE                    ((uint16_t)128)
+
 /* Heap size determined automatically by linker */
 // #define configTOTAL_HEAP_SIZE                    ((size_t)0)
-#define configMAX_TASK_NAME_LEN                  ( 16 )
-#define configGENERATE_RUN_TIME_STATS            0
-#define configUSE_TRACE_FACILITY                 1
-#define configUSE_16_BIT_TICKS                   0
-#define configUSE_MUTEXES                        1
-#define configQUEUE_REGISTRY_SIZE                8
-#define configCHECK_FOR_STACK_OVERFLOW           1
-#define configUSE_RECURSIVE_MUTEXES              1
-#define configUSE_COUNTING_SEMAPHORES            1
-#define configENABLE_BACKWARD_COMPATIBILITY      0
-#define configUSE_PORT_OPTIMISED_TASK_SELECTION  0
-#define configUSE_TICKLESS_IDLE                  2
-#define configRECORD_STACK_HIGH_ADDRESS          1
-#define configUSE_NEWLIB_REENTRANT               0
-/* USER CODE BEGIN MESSAGE_BUFFER_LENGTH_TYPE */
+#define configMAX_TASK_NAME_LEN                     ( 16 )
+#define configGENERATE_RUN_TIME_STATS               0
+#define configUSE_TRACE_FACILITY                    1
+#define configUSE_16_BIT_TICKS                      0
+#define configUSE_MUTEXES                           1
+#define configQUEUE_REGISTRY_SIZE                   8
+#define configCHECK_FOR_STACK_OVERFLOW              1
+#define configUSE_RECURSIVE_MUTEXES                 1
+#define configUSE_COUNTING_SEMAPHORES               1
+#define configENABLE_BACKWARD_COMPATIBILITY         0
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION     0
+#define configUSE_TICKLESS_IDLE                     2
+#define configRECORD_STACK_HIGH_ADDRESS             1
+#define configUSE_NEWLIB_REENTRANT                  0
+
 /* Defaults to size_t for backward compatibility, but can be changed
    if lengths will always be less than the number of bytes in a size_t. */
-#define configMESSAGE_BUFFER_LENGTH_TYPE         size_t
-#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 1
-#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP   8
-/* USER CODE END MESSAGE_BUFFER_LENGTH_TYPE */
+#define configMESSAGE_BUFFER_LENGTH_TYPE            size_t
+#define configNUM_THREAD_LOCAL_STORAGE_POINTERS     1
+#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP       4
 
 /* Co-routine definitions. */
-#define configUSE_CO_ROUTINES                    0
-#define configMAX_CO_ROUTINE_PRIORITIES          ( 2 )
+#define configUSE_CO_ROUTINES                       0
 
 /* Software timer definitions. */
-#define configUSE_TIMERS                         1
-#define configTIMER_TASK_PRIORITY                ( 2 )
-#define configTIMER_QUEUE_LENGTH                 32
-#define configTIMER_TASK_STACK_DEPTH             256
-#define configTIMER_SERVICE_TASK_NAME          "TimersSrv"
+#define configUSE_TIMERS                            1
+#define configTIMER_TASK_PRIORITY                   ( 2 )
+#define configTIMER_QUEUE_LENGTH                    32
+#define configTIMER_TASK_STACK_DEPTH                256
+#define configTIMER_SERVICE_TASK_NAME               "TimersSrv"
 
-#define configIDLE_TASK_NAME                  "(-_-)"
+#define configIDLE_TASK_NAME                        "(-_-)"
 
 /* Set the following definitions to 1 to include the API function, or zero
 to exclude the API function. */
-#define INCLUDE_eTaskGetState                1
-#define INCLUDE_uxTaskGetStackHighWaterMark  1
-#define INCLUDE_uxTaskPriorityGet            1
-#define INCLUDE_vTaskCleanUpResources        0
-#define INCLUDE_vTaskDelay                   1
-#define INCLUDE_vTaskDelayUntil              1
-#define INCLUDE_vTaskDelete                  1
-#define INCLUDE_vTaskPrioritySet             1
-#define INCLUDE_vTaskSuspend                 1
-#define INCLUDE_xQueueGetMutexHolder         1
-#define INCLUDE_xTaskGetCurrentTaskHandle    1
-#define INCLUDE_xTaskGetSchedulerState       1
-#define INCLUDE_xTimerPendFunctionCall       1
+#define INCLUDE_eTaskGetState                       1
+#define INCLUDE_uxTaskGetStackHighWaterMark         1
+#define INCLUDE_uxTaskPriorityGet                   1
+#define INCLUDE_vTaskCleanUpResources               0
+#define INCLUDE_vTaskDelay                          1
+#define INCLUDE_vTaskDelayUntil                     1
+#define INCLUDE_vTaskDelete                         1
+#define INCLUDE_vTaskPrioritySet                    1
+#define INCLUDE_vTaskSuspend                        1
+#define INCLUDE_xQueueGetMutexHolder                1
+#define INCLUDE_xTaskGetCurrentTaskHandle           1
+#define INCLUDE_xTaskGetSchedulerState              1
+#define INCLUDE_xTimerPendFunctionCall              1
 
 /* CMSIS-RTOS V2 flags */
-#define configUSE_OS2_THREAD_SUSPEND_RESUME  1
-#define configUSE_OS2_THREAD_ENUMERATE       1
-#define configUSE_OS2_EVENTFLAGS_FROM_ISR    1
-#define configUSE_OS2_THREAD_FLAGS           1
-#define configUSE_OS2_TIMER                  1
-#define configUSE_OS2_MUTEX                  1
+#define configUSE_OS2_THREAD_SUSPEND_RESUME         1
+#define configUSE_OS2_THREAD_ENUMERATE              1
+#define configUSE_OS2_EVENTFLAGS_FROM_ISR           1
+#define configUSE_OS2_THREAD_FLAGS                  1
+#define configUSE_OS2_TIMER                         1
+#define configUSE_OS2_MUTEX                         1
+
+/* CMSIS-RTOS */
+#define configTASK_NOTIFICATION_ARRAY_ENTRIES       2
+#define CMSIS_TASK_NOTIFY_INDEX 1
 
 /*
  * The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used
@@ -137,15 +93,15 @@ to exclude the API function. */
 
 /* Cortex-M specific definitions. */
 #ifdef __NVIC_PRIO_BITS
- /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
- #define configPRIO_BITS         __NVIC_PRIO_BITS
+    /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
+    #define configPRIO_BITS                         __NVIC_PRIO_BITS
 #else
- #define configPRIO_BITS         4
+    #define configPRIO_BITS                         4
 #endif
 
 /* The lowest interrupt priority that can be used in a call to a "set priority"
 function. */
-#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   15
+#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY     15
 
 /* The highest interrupt priority that can be used by any interrupt service
 routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
@@ -155,29 +111,20 @@ PRIORITY THAN THIS! (higher priorities are lower numeric values. */
 
 /* Interrupt priorities used by the kernel port layer itself.  These are generic
 to all Cortex-M ports, and do not rely on any particular library functions. */
-#define configKERNEL_INTERRUPT_PRIORITY         ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
+#define configKERNEL_INTERRUPT_PRIORITY             ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
+
 /* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
 See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
-#define configMAX_SYSCALL_INTERRUPT_PRIORITY    ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
+#define configMAX_SYSCALL_INTERRUPT_PRIORITY        ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
 
 /* Normal assert() semantics without relying on the provision of an assert.h
 header file. */
-/* USER CODE BEGIN 1 */
-#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); asm("bkpt 1"); for( ;; );}
-/* USER CODE END 1 */
+#define configASSERT( x ) if ((x) == 0) { taskDISABLE_INTERRUPTS(); asm("bkpt 1"); for( ;; ); }
 
 /* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
 standard names. */
 #define vPortSVCHandler    SVC_Handler
 #define xPortPendSVHandler PendSV_Handler
 
-/* IMPORTANT: After 10.3.1 update, Systick_Handler comes from NVIC (if SYS timebase = systick), otherwise from cmsis_os2.c */
-
 #define USE_CUSTOM_SYSTICK_HANDLER_IMPLEMENTATION 1
-
-/* USER CODE BEGIN Defines */
-/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */
 #define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 1  /* required only for Keil but does not hurt otherwise */
-/* USER CODE END Defines */
-
-#endif /* FREERTOS_CONFIG_H */

+ 0 - 21
firmware/targets/f7/Src/freertos-openocd.c

@@ -1,21 +0,0 @@
-
-/*
- * Since at least FreeRTOS V7.5.3 uxTopUsedPriority is no longer
- * present in the kernel, so it has to be supplied by other means for
- * OpenOCD's threads awareness.
- *
- * Add this file to your project, and, if you're using --gc-sections,
- * ``--undefined=uxTopUsedPriority'' (or
- * ``-Wl,--undefined=uxTopUsedPriority'' when using gcc for final
- * linking) to your LDFLAGS; same with all the other symbols you need.
- */
-
-#include "FreeRTOS.h"
-
-#ifdef __GNUC__
-#define USED __attribute__((used))
-#else
-#define USED
-#endif
-
-const int USED uxTopUsedPriority = configMAX_PRIORITIES - 1;

+ 0 - 1
firmware/targets/f7/ble-glue/ble_app.c

@@ -3,7 +3,6 @@
 #include "hci_tl.h"
 #include "ble.h"
 #include "shci.h"
-#include "cmsis_os.h"
 #include "gap.h"
 
 #include <furi-hal.h>

+ 0 - 1
firmware/targets/f7/ble-glue/ble_glue.c

@@ -5,7 +5,6 @@
 #include "ble.h"
 #include "tl.h"
 #include "shci.h"
-#include "cmsis_os.h"
 #include "shci_tl.h"
 #include "app_debug.h"
 #include <furi-hal.h>

+ 2 - 3
firmware/targets/f7/ble-glue/gap.c

@@ -2,7 +2,6 @@
 
 #include "ble.h"
 
-#include "cmsis_os.h"
 #include <furi-hal.h>
 #include <furi.h>
 
@@ -28,7 +27,7 @@ typedef struct {
     osMutexId_t state_mutex;
     BleEventCallback on_event_cb;
     void* context;
-    osTimerId advertise_timer;
+    osTimerId_t advertise_timer;
     FuriThread* thread;
     osMessageQueueId_t command_queue;
     bool enable_adv;
@@ -446,7 +445,7 @@ void gap_thread_stop() {
 static int32_t gap_app(void *context) {
     GapCommand command;
     while(1) {
-        osStatus status = osMessageQueueGet(gap->command_queue, &command, NULL, osWaitForever);
+        osStatus_t status = osMessageQueueGet(gap->command_queue, &command, NULL, osWaitForever);
         if(status != osOK) {
             FURI_LOG_E(TAG, "Message queue get error: %d", status);
             continue;

+ 1 - 1
firmware/targets/f7/ble-glue/serial_service.c

@@ -62,7 +62,7 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void *event) {
                 ret = SVCCTL_EvtAckFlowEnable;
             }
         } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) {
-            FURI_LOG_D(TAG, "Ack received", blecore_evt->ecode);
+            FURI_LOG_T(TAG, "Ack received", blecore_evt->ecode);
             if(serial_svc->callback) {
                 SerialServiceEvent event = {
                     .event = SerialServiceEventTypeDataSent,

+ 0 - 1
firmware/targets/f7/fatfs/ffconf.h

@@ -26,7 +26,6 @@
 
 #include "main.h"
 #include "stm32wbxx_hal.h"
-#include "cmsis_os.h" /* _FS_REENTRANT set to 1 and CMSIS API chosen */
 
 /*-----------------------------------------------------------------------------/
 / Function Configurations

+ 2 - 2
firmware/targets/f7/furi-hal/furi-hal-os.c

@@ -43,7 +43,7 @@ void furi_hal_os_init() {
     LL_GPIO_SetPinMode(LED_TICK_PORT, LED_TICK_PIN, LL_GPIO_MODE_OUTPUT);
     LL_GPIO_SetPinMode(LED_SECOND_PORT, LED_SECOND_PIN, LL_GPIO_MODE_OUTPUT);
     osTimerId_t second_timer = osTimerNew(furi_hal_os_timer_callback, osTimerPeriodic, NULL, NULL);
-    osTimerStart(second_timer, 1024);
+    osTimerStart(second_timer, FURI_HAL_OS_TICK_PER_SECOND);
 #endif
 
     FURI_LOG_I(TAG, "Init OK");
@@ -139,7 +139,7 @@ void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) {
     __enable_irq();
 }
 
-void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName) {
+void vApplicationStackOverflowHook(TaskHandle_t xTask, char * pcTaskName) {
     asm("bkpt 1");
     while(1) {};
 }

+ 0 - 1
firmware/targets/f7/furi-hal/furi-hal-task.c

@@ -1,4 +1,3 @@
-#include "cmsis_os.h"
 #include "furi-hal-task.h"
 
 //-----------------------------cmsis_os2.c-------------------------------

+ 12 - 11
firmware/targets/f7/target.mk

@@ -75,18 +75,19 @@ C_SOURCES += \
 
 # FreeRTOS
 CFLAGS += \
-	-I$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/include \
-	-I$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 \
-	-I$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F
+	-I$(LIB_DIR)/FreeRTOS-Kernel/include \
+	-I$(LIB_DIR)/FreeRTOS-Kernel/portable/GCC/ARM_CM4F \
+	-I$(LIB_DIR)/FreeRTOS-glue/
+
 C_SOURCES += \
-	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \
-	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/list.c \
-	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/queue.c \
-	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c \
-	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/tasks.c \
-	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/timers.c \
-	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c \
-	$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c
+	$(LIB_DIR)/FreeRTOS-Kernel/event_groups.c \
+	$(LIB_DIR)/FreeRTOS-Kernel/list.c \
+	$(LIB_DIR)/FreeRTOS-Kernel/queue.c \
+	$(LIB_DIR)/FreeRTOS-Kernel/stream_buffer.c \
+	$(LIB_DIR)/FreeRTOS-Kernel/tasks.c \
+	$(LIB_DIR)/FreeRTOS-Kernel/timers.c \
+	$(LIB_DIR)/FreeRTOS-Kernel/portable/GCC/ARM_CM4F/port.c \
+	$(LIB_DIR)/FreeRTOS-glue/cmsis_os2.c \
 
 # BLE glue 
 CFLAGS += \

+ 1 - 0
lib/FreeRTOS-Kernel

@@ -0,0 +1 @@
+Subproject commit 4c4089b1544b590ed3b72491a15365ec020c921f

+ 2873 - 0
lib/FreeRTOS-glue/cmsis_os2.c

@@ -0,0 +1,2873 @@
+/* --------------------------------------------------------------------------
+ * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *      Name:    cmsis_os2.c
+ *      Purpose: CMSIS RTOS2 wrapper for FreeRTOS
+ *
+ *---------------------------------------------------------------------------*/
+
+#include <string.h>
+
+#include "cmsis_os2.h"                  // ::CMSIS:RTOS2
+#include "cmsis_compiler.h"             // Compiler agnostic definitions
+#include "os_tick.h"                    // OS Tick API
+
+#include "FreeRTOS.h"                   // ARM.FreeRTOS::RTOS:Core
+#include "task.h"                       // ARM.FreeRTOS::RTOS:Core
+#include "event_groups.h"               // ARM.FreeRTOS::RTOS:Event Groups
+#include "semphr.h"                     // ARM.FreeRTOS::RTOS:Core
+#include "timers.h"                     // ARM.FreeRTOS::RTOS:Timers
+
+#include "freertos_mpool.h"             // osMemoryPool definitions
+#include "freertos_os2.h"               // Configuration check and setup
+
+#include CMSIS_device_header
+
+#ifndef CMSIS_TASK_NOTIFY_INDEX
+#define CMSIS_TASK_NOTIFY_INDEX 0
+#endif
+
+/*---------------------------------------------------------------------------*/
+#ifndef __ARM_ARCH_6M__
+  #define __ARM_ARCH_6M__         0
+#endif
+#ifndef __ARM_ARCH_7M__
+  #define __ARM_ARCH_7M__         0
+#endif
+#ifndef __ARM_ARCH_7EM__
+  #define __ARM_ARCH_7EM__        0
+#endif
+#ifndef __ARM_ARCH_8M_MAIN__
+  #define __ARM_ARCH_8M_MAIN__    0
+#endif
+#ifndef __ARM_ARCH_7A__
+  #define __ARM_ARCH_7A__         0
+#endif
+
+#if   ((__ARM_ARCH_7M__      == 1U) || \
+       (__ARM_ARCH_7EM__     == 1U) || \
+       (__ARM_ARCH_8M_MAIN__ == 1U))
+#define IS_IRQ_MASKED()           ((__get_PRIMASK() != 0U) || (__get_BASEPRI() != 0U))
+#elif  (__ARM_ARCH_6M__      == 1U)
+#define IS_IRQ_MASKED()           (__get_PRIMASK() != 0U)
+#elif (__ARM_ARCH_7A__       == 1U)
+/* CPSR mask bits */
+#define CPSR_MASKBIT_I            0x80U
+
+#define IS_IRQ_MASKED()           ((__get_CPSR() & CPSR_MASKBIT_I) != 0U)
+#else
+#define IS_IRQ_MASKED()           (__get_PRIMASK() != 0U)
+#endif
+
+#if    (__ARM_ARCH_7A__      == 1U)
+/* CPSR mode bitmasks */
+#define CPSR_MODE_USER            0x10U
+#define CPSR_MODE_SYSTEM          0x1FU
+
+#define IS_IRQ_MODE()             ((__get_mode() != CPSR_MODE_USER) && (__get_mode() != CPSR_MODE_SYSTEM))
+#else
+#define IS_IRQ_MODE()             (__get_IPSR() != 0U)
+#endif
+
+/* Limits */
+#define MAX_BITS_TASK_NOTIFY      31U
+#define MAX_BITS_EVENT_GROUPS     24U
+
+#define THREAD_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_TASK_NOTIFY)  - 1U))
+#define EVENT_FLAGS_INVALID_BITS  (~((1UL << MAX_BITS_EVENT_GROUPS) - 1U))
+
+/* Kernel version and identification string definition (major.minor.rev: mmnnnrrrr dec) */
+#define KERNEL_VERSION            (((uint32_t)tskKERNEL_VERSION_MAJOR * 10000000UL) | \
+                                   ((uint32_t)tskKERNEL_VERSION_MINOR *    10000UL) | \
+                                   ((uint32_t)tskKERNEL_VERSION_BUILD *        1UL))
+
+#define KERNEL_ID                 ("FreeRTOS " tskKERNEL_VERSION_NUMBER)
+
+/* Timer callback information structure definition */
+typedef struct {
+  osTimerFunc_t func;
+  void         *arg;
+} TimerCallback_t;
+
+/* Kernel initialization state */
+static osKernelState_t KernelState = osKernelInactive;
+
+/*
+  Heap region definition used by heap_5 variant
+
+  Define configAPPLICATION_ALLOCATED_HEAP as nonzero value in FreeRTOSConfig.h if
+  heap regions are already defined and vPortDefineHeapRegions is called in application.
+
+  Otherwise vPortDefineHeapRegions will be called by osKernelInitialize using
+  definition configHEAP_5_REGIONS as parameter. Overriding configHEAP_5_REGIONS
+  is possible by defining it globally or in FreeRTOSConfig.h.
+*/
+#if defined(USE_FreeRTOS_HEAP_5)
+#if (configAPPLICATION_ALLOCATED_HEAP == 0)
+  /*
+    FreeRTOS heap is not defined by the application.
+    Single region of size configTOTAL_HEAP_SIZE (defined in FreeRTOSConfig.h)
+    is provided by default. Define configHEAP_5_REGIONS to provide custom
+    HeapRegion_t array.
+  */
+  #define HEAP_5_REGION_SETUP   1
+  
+  #ifndef configHEAP_5_REGIONS
+    #define configHEAP_5_REGIONS xHeapRegions
+
+    static uint8_t ucHeap[configTOTAL_HEAP_SIZE];
+
+    static HeapRegion_t xHeapRegions[] = {
+      { ucHeap, configTOTAL_HEAP_SIZE },
+      { NULL,   0                     }
+    };
+  #else
+    /* Global definition is provided to override default heap array */
+    extern HeapRegion_t configHEAP_5_REGIONS[];
+  #endif
+#else
+  /*
+    The application already defined the array used for the FreeRTOS heap and
+    called vPortDefineHeapRegions to initialize heap.
+  */
+  #define HEAP_5_REGION_SETUP   0
+#endif /* configAPPLICATION_ALLOCATED_HEAP */
+#endif /* USE_FreeRTOS_HEAP_5 */
+
+/*
+  Setup SVC to reset value.
+*/
+__STATIC_INLINE void SVC_Setup (void) {
+#if (__ARM_ARCH_7A__ == 0U)
+  /* Service Call interrupt might be configured before kernel start     */
+  /* and when its priority is lower or equal to BASEPRI, svc intruction */
+  /* causes a Hard Fault.                                               */
+  NVIC_SetPriority (SVCall_IRQn, 0U);
+#endif
+}
+
+/*
+  Function macro used to retrieve semaphore count from ISR
+*/
+#ifndef uxSemaphoreGetCountFromISR
+#define uxSemaphoreGetCountFromISR( xSemaphore ) uxQueueMessagesWaitingFromISR( ( QueueHandle_t ) ( xSemaphore ) )
+#endif
+
+/*
+  Determine if CPU executes from interrupt context or if interrupts are masked.
+*/
+__STATIC_INLINE uint32_t IRQ_Context (void) {
+  uint32_t irq;
+  BaseType_t state;
+
+  irq = 0U;
+
+  if (IS_IRQ_MODE()) {
+    /* Called from interrupt context */
+    irq = 1U;
+  }
+  else {
+    /* Get FreeRTOS scheduler state */
+    state = xTaskGetSchedulerState();
+
+    if (state != taskSCHEDULER_NOT_STARTED) {
+      /* Scheduler was started */
+      if (IS_IRQ_MASKED()) {
+        /* Interrupts are masked */
+        irq = 1U;
+      }
+    }
+  }
+
+  /* Return context, 0: thread context, 1: IRQ context */
+  return (irq);
+}
+
+
+/* ==== Kernel Management Functions ==== */
+
+/*
+  Initialize the RTOS Kernel.
+*/
+osStatus_t osKernelInitialize (void) {
+  osStatus_t stat;
+  BaseType_t state;
+
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else {
+    state = xTaskGetSchedulerState();
+
+    /* Initialize if scheduler not started and not initialized before */
+    if ((state == taskSCHEDULER_NOT_STARTED) && (KernelState == osKernelInactive)) {
+      #if defined(USE_TRACE_EVENT_RECORDER)
+        /* Initialize the trace macro debugging output channel */
+        EvrFreeRTOSSetup(0U);
+      #endif
+      #if defined(USE_FreeRTOS_HEAP_5) && (HEAP_5_REGION_SETUP == 1)
+        /* Initialize the memory regions when using heap_5 variant */
+        vPortDefineHeapRegions (configHEAP_5_REGIONS);
+      #endif
+      KernelState = osKernelReady;
+      stat = osOK;
+    } else {
+      stat = osError;
+    }
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+/*
+  Get RTOS Kernel Information.
+*/
+osStatus_t osKernelGetInfo (osVersion_t *version, char *id_buf, uint32_t id_size) {
+
+  if (version != NULL) {
+    /* Version encoding is major.minor.rev: mmnnnrrrr dec */
+    version->api    = KERNEL_VERSION;
+    version->kernel = KERNEL_VERSION;
+  }
+
+  if ((id_buf != NULL) && (id_size != 0U)) {
+    /* Buffer for retrieving identification string is provided */
+    if (id_size > sizeof(KERNEL_ID)) {
+      id_size = sizeof(KERNEL_ID);
+    }
+    /* Copy kernel identification string into provided buffer */
+    memcpy(id_buf, KERNEL_ID, id_size);
+  }
+
+  /* Return execution status */
+  return (osOK);
+}
+
+/*
+  Get the current RTOS Kernel state.
+*/
+osKernelState_t osKernelGetState (void) {
+  osKernelState_t state;
+
+  switch (xTaskGetSchedulerState()) {
+    case taskSCHEDULER_RUNNING:
+      state = osKernelRunning;
+      break;
+
+    case taskSCHEDULER_SUSPENDED:
+      state = osKernelLocked;
+      break;
+
+    case taskSCHEDULER_NOT_STARTED:
+    default:
+      if (KernelState == osKernelReady) {
+        /* Ready, osKernelInitialize was already called */
+        state = osKernelReady;
+      } else {
+        /* Not initialized */
+        state = osKernelInactive;
+      }
+      break;
+  }
+
+  /* Return current state */
+  return (state);
+}
+
+/*
+  Start the RTOS Kernel scheduler.
+*/
+osStatus_t osKernelStart (void) {
+  osStatus_t stat;
+  BaseType_t state;
+
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else {
+    state = xTaskGetSchedulerState();
+
+    /* Start scheduler if initialized and not started before */
+    if ((state == taskSCHEDULER_NOT_STARTED) && (KernelState == osKernelReady)) {
+      /* Ensure SVC priority is at the reset value */
+      SVC_Setup();
+      /* Change state to ensure correct API flow */
+      KernelState = osKernelRunning;
+      /* Start the kernel scheduler */
+      vTaskStartScheduler();
+      stat = osOK;
+    } else {
+      stat = osError;
+    }
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+/*
+  Lock the RTOS Kernel scheduler.
+*/
+int32_t osKernelLock (void) {
+  int32_t lock;
+
+  if (IRQ_Context() != 0U) {
+    lock = (int32_t)osErrorISR;
+  }
+  else {
+    switch (xTaskGetSchedulerState()) {
+      case taskSCHEDULER_SUSPENDED:
+        lock = 1;
+        break;
+
+      case taskSCHEDULER_RUNNING:
+        vTaskSuspendAll();
+        lock = 0;
+        break;
+
+      case taskSCHEDULER_NOT_STARTED:
+      default:
+        lock = (int32_t)osError;
+        break;
+    }
+  }
+
+  /* Return previous lock state */
+  return (lock);
+}
+
+/*
+  Unlock the RTOS Kernel scheduler.
+*/
+int32_t osKernelUnlock (void) {
+  int32_t lock;
+
+  if (IRQ_Context() != 0U) {
+    lock = (int32_t)osErrorISR;
+  }
+  else {
+    switch (xTaskGetSchedulerState()) {
+      case taskSCHEDULER_SUSPENDED:
+        lock = 1;
+
+        if (xTaskResumeAll() != pdTRUE) {
+          if (xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED) {
+            lock = (int32_t)osError;
+          }
+        }
+        break;
+
+      case taskSCHEDULER_RUNNING:
+        lock = 0;
+        break;
+
+      case taskSCHEDULER_NOT_STARTED:
+      default:
+        lock = (int32_t)osError;
+        break;
+    }
+  }
+
+  /* Return previous lock state */
+  return (lock);
+}
+
+/*
+  Restore the RTOS Kernel scheduler lock state.
+*/
+int32_t osKernelRestoreLock (int32_t lock) {
+
+  if (IRQ_Context() != 0U) {
+    lock = (int32_t)osErrorISR;
+  }
+  else {
+    switch (xTaskGetSchedulerState()) {
+      case taskSCHEDULER_SUSPENDED:
+      case taskSCHEDULER_RUNNING:
+        if (lock == 1) {
+          vTaskSuspendAll();
+        }
+        else {
+          if (lock != 0) {
+            lock = (int32_t)osError;
+          }
+          else {
+            if (xTaskResumeAll() != pdTRUE) {
+              if (xTaskGetSchedulerState() != taskSCHEDULER_RUNNING) {
+                lock = (int32_t)osError;
+              }
+            }
+          }
+        }
+        break;
+
+      case taskSCHEDULER_NOT_STARTED:
+      default:
+        lock = (int32_t)osError;
+        break;
+    }
+  }
+
+  /* Return new lock state */
+  return (lock);
+}
+
+/*
+  Get the RTOS kernel tick count.
+*/
+uint32_t osKernelGetTickCount (void) {
+  TickType_t ticks;
+
+  if (IRQ_Context() != 0U) {
+    ticks = xTaskGetTickCountFromISR();
+  } else {
+    ticks = xTaskGetTickCount();
+  }
+
+  /* Return kernel tick count */
+  return (ticks);
+}
+
+/*
+  Get the RTOS kernel tick frequency.
+*/
+uint32_t osKernelGetTickFreq (void) {
+  /* Return frequency in hertz */
+  return (configTICK_RATE_HZ);
+}
+
+/*
+  Get the RTOS kernel system timer count.
+*/
+uint32_t osKernelGetSysTimerCount (void) {
+  uint32_t irqmask = IS_IRQ_MASKED();
+  TickType_t ticks;
+  uint32_t val;
+
+  __disable_irq();
+
+  ticks = xTaskGetTickCount();
+  val   = OS_Tick_GetCount();
+
+  /* Update tick count and timer value when timer overflows */
+  if (OS_Tick_GetOverflow() != 0U) {
+    val = OS_Tick_GetCount();
+    ticks++;
+  }
+  val += ticks * OS_Tick_GetInterval();
+
+  if (irqmask == 0U) {
+    __enable_irq();
+  }
+
+  /* Return system timer count */
+  return (val);
+}
+
+/*
+  Get the RTOS kernel system timer frequency.
+*/
+uint32_t osKernelGetSysTimerFreq (void) {
+  /* Return frequency in hertz */
+  return (configCPU_CLOCK_HZ);
+}
+
+
+/* ==== Thread Management Functions ==== */
+
+/*
+  Create a thread and add it to Active Threads.
+
+  Limitations:
+  - The memory for control block and stack must be provided in the osThreadAttr_t
+    structure in order to allocate object statically.
+  - Attribute osThreadJoinable is not supported, NULL is returned if used.
+*/
+osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr) {
+  const char *name;
+  uint32_t stack;
+  TaskHandle_t hTask;
+  UBaseType_t prio;
+  int32_t mem;
+
+  hTask = NULL;
+
+  if ((IRQ_Context() == 0U) && (func != NULL)) {
+    stack = configMINIMAL_STACK_SIZE;
+    prio  = (UBaseType_t)osPriorityNormal;
+
+    name = NULL;
+    mem  = -1;
+
+    if (attr != NULL) {
+      if (attr->name != NULL) {
+        name = attr->name;
+      }
+      if (attr->priority != osPriorityNone) {
+        prio = (UBaseType_t)attr->priority;
+      }
+
+      if ((prio < osPriorityIdle) || (prio > osPriorityISR) || ((attr->attr_bits & osThreadJoinable) == osThreadJoinable)) {
+        /* Invalid priority or unsupported osThreadJoinable attribute used */
+        return (NULL);
+      }
+
+      if (attr->stack_size > 0U) {
+        /* In FreeRTOS stack is not in bytes, but in sizeof(StackType_t) which is 4 on ARM ports.       */
+        /* Stack size should be therefore 4 byte aligned in order to avoid division caused side effects */
+        stack = attr->stack_size / sizeof(StackType_t);
+      }
+
+      if ((attr->cb_mem    != NULL) && (attr->cb_size    >= sizeof(StaticTask_t)) &&
+          (attr->stack_mem != NULL) && (attr->stack_size >  0U)) {
+        /* The memory for control block and stack is provided, use static object */
+        mem = 1;
+      }
+      else {
+        if ((attr->cb_mem == NULL) && (attr->cb_size == 0U) && (attr->stack_mem == NULL)) {
+          /* Control block and stack memory will be allocated from the dynamic pool */
+          mem = 0;
+        }
+      }
+    }
+    else {
+      mem = 0;
+    }
+
+    if (mem == 1) {
+      #if (configSUPPORT_STATIC_ALLOCATION == 1)
+        hTask = xTaskCreateStatic ((TaskFunction_t)func, name, stack, argument, prio, (StackType_t  *)attr->stack_mem,
+                                                                                      (StaticTask_t *)attr->cb_mem);
+      #endif
+    }
+    else {
+      if (mem == 0) {
+        #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
+          if (xTaskCreate ((TaskFunction_t)func, name, (configSTACK_DEPTH_TYPE)stack, argument, prio, &hTask) != pdPASS) {
+            hTask = NULL;
+          }
+        #endif
+      }
+    }
+  }
+
+  /* Return thread ID */
+  return ((osThreadId_t)hTask);
+}
+
+/*
+  Get name of a thread.
+*/
+const char *osThreadGetName (osThreadId_t thread_id) {
+  TaskHandle_t hTask = (TaskHandle_t)thread_id;
+  const char *name;
+
+  if ((IRQ_Context() != 0U) || (hTask == NULL)) {
+    name = NULL;
+  } else {
+    name = pcTaskGetName (hTask);
+  }
+
+  /* Return name as null-terminated string */
+  return (name);
+}
+
+/*
+  Return the thread ID of the current running thread.
+*/
+osThreadId_t osThreadGetId (void) {
+  osThreadId_t id;
+
+  id = (osThreadId_t)xTaskGetCurrentTaskHandle();
+
+  /* Return thread ID */
+  return (id);
+}
+
+/*
+  Get current thread state of a thread.
+*/
+osThreadState_t osThreadGetState (osThreadId_t thread_id) {
+  TaskHandle_t hTask = (TaskHandle_t)thread_id;
+  osThreadState_t state;
+
+  if ((IRQ_Context() != 0U) || (hTask == NULL)) {
+    state = osThreadError;
+  }
+  else {
+    switch (eTaskGetState (hTask)) {
+      case eRunning:   state = osThreadRunning;    break;
+      case eReady:     state = osThreadReady;      break;
+      case eBlocked:
+      case eSuspended: state = osThreadBlocked;    break;
+      case eDeleted:   state = osThreadTerminated; break;
+      case eInvalid:
+      default:         state = osThreadError;      break;
+    }
+  }
+
+  /* Return current thread state */
+  return (state);
+}
+
+/*
+  Get available stack space of a thread based on stack watermark recording during execution.
+*/
+uint32_t osThreadGetStackSpace (osThreadId_t thread_id) {
+  TaskHandle_t hTask = (TaskHandle_t)thread_id;
+  uint32_t sz;
+
+  if ((IRQ_Context() != 0U) || (hTask == NULL)) {
+    sz = 0U;
+  } else {
+    sz = (uint32_t)(uxTaskGetStackHighWaterMark(hTask) * sizeof(StackType_t));
+  }
+
+  /* Return remaining stack space in bytes */
+  return (sz);
+}
+
+/*
+  Change priority of a thread.
+*/
+osStatus_t osThreadSetPriority (osThreadId_t thread_id, osPriority_t priority) {
+  TaskHandle_t hTask = (TaskHandle_t)thread_id;
+  osStatus_t stat;
+
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else if ((hTask == NULL) || (priority < osPriorityIdle) || (priority > osPriorityISR)) {
+    stat = osErrorParameter;
+  }
+  else {
+    stat = osOK;
+    vTaskPrioritySet (hTask, (UBaseType_t)priority);
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+/*
+  Get current priority of a thread.
+*/
+osPriority_t osThreadGetPriority (osThreadId_t thread_id) {
+  TaskHandle_t hTask = (TaskHandle_t)thread_id;
+  osPriority_t prio;
+
+  if ((IRQ_Context() != 0U) || (hTask == NULL)) {
+    prio = osPriorityError;
+  } else {
+    prio = (osPriority_t)((int32_t)uxTaskPriorityGet (hTask));
+  }
+
+  /* Return current thread priority */
+  return (prio);
+}
+
+/*
+  Pass control to next thread that is in state READY.
+*/
+osStatus_t osThreadYield (void) {
+  osStatus_t stat;
+
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  } else {
+    stat = osOK;
+    taskYIELD();
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+#if (configUSE_OS2_THREAD_SUSPEND_RESUME == 1)
+/*
+  Suspend execution of a thread.
+*/
+osStatus_t osThreadSuspend (osThreadId_t thread_id) {
+  TaskHandle_t hTask = (TaskHandle_t)thread_id;
+  osStatus_t stat;
+
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else if (hTask == NULL) {
+    stat = osErrorParameter;
+  }
+  else {
+    stat = osOK;
+    vTaskSuspend (hTask);
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+/*
+  Resume execution of a thread.
+*/
+osStatus_t osThreadResume (osThreadId_t thread_id) {
+  TaskHandle_t hTask = (TaskHandle_t)thread_id;
+  osStatus_t stat;
+
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else if (hTask == NULL) {
+    stat = osErrorParameter;
+  }
+  else {
+    stat = osOK;
+    vTaskResume (hTask);
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+#endif /* (configUSE_OS2_THREAD_SUSPEND_RESUME == 1) */
+
+/*
+  Terminate execution of current running thread.
+*/
+__NO_RETURN void osThreadExit (void) {
+#ifndef USE_FreeRTOS_HEAP_1
+  vTaskDelete (NULL);
+#endif
+  for (;;);
+}
+
+/*
+  Terminate execution of a thread.
+*/
+osStatus_t osThreadTerminate (osThreadId_t thread_id) {
+  TaskHandle_t hTask = (TaskHandle_t)thread_id;
+  osStatus_t stat;
+#ifndef USE_FreeRTOS_HEAP_1
+  eTaskState tstate;
+
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else if (hTask == NULL) {
+    stat = osErrorParameter;
+  }
+  else {
+    tstate = eTaskGetState (hTask);
+
+    if (tstate != eDeleted) {
+      stat = osOK;
+      vTaskDelete (hTask);
+    } else {
+      stat = osErrorResource;
+    }
+  }
+#else
+  stat = osError;
+#endif
+
+  /* Return execution status */
+  return (stat);
+}
+
+/*
+  Get number of active threads.
+*/
+uint32_t osThreadGetCount (void) {
+  uint32_t count;
+
+  if (IRQ_Context() != 0U) {
+    count = 0U;
+  } else {
+    count = uxTaskGetNumberOfTasks();
+  }
+
+  /* Return number of active threads */
+  return (count);
+}
+
+#if (configUSE_OS2_THREAD_ENUMERATE == 1)
+/*
+  Enumerate active threads.
+*/
+uint32_t osThreadEnumerate (osThreadId_t *thread_array, uint32_t array_items) {
+  uint32_t i, count;
+  TaskStatus_t *task;
+
+  if ((IRQ_Context() != 0U) || (thread_array == NULL) || (array_items == 0U)) {
+    count = 0U;
+  } else {
+    vTaskSuspendAll();
+
+    /* Allocate memory on heap to temporarily store TaskStatus_t information */
+    count = uxTaskGetNumberOfTasks();
+    task  = pvPortMalloc (count * sizeof(TaskStatus_t));
+
+    if (task != NULL) {
+      /* Retrieve task status information */
+      count = uxTaskGetSystemState (task, count, NULL);
+
+      /* Copy handles from task status array into provided thread array */
+      for (i = 0U; (i < count) && (i < array_items); i++) {
+        thread_array[i] = (osThreadId_t)task[i].xHandle;
+      }
+      count = i;
+    }
+    (void)xTaskResumeAll();
+
+    vPortFree (task);
+  }
+
+  /* Return number of enumerated threads */
+  return (count);
+}
+#endif /* (configUSE_OS2_THREAD_ENUMERATE == 1) */
+
+
+/* ==== Thread Flags Functions ==== */
+
+#if (configUSE_OS2_THREAD_FLAGS == 1)
+/*
+  Set the specified Thread Flags of a thread.
+*/
+uint32_t osThreadFlagsSet (osThreadId_t thread_id, uint32_t flags) {
+  TaskHandle_t hTask = (TaskHandle_t)thread_id;
+  uint32_t rflags;
+  BaseType_t yield;
+
+  if ((hTask == NULL) || ((flags & THREAD_FLAGS_INVALID_BITS) != 0U)) {
+    rflags = (uint32_t)osErrorParameter;
+  }
+  else {
+    rflags = (uint32_t)osError;
+
+    if (IRQ_Context() != 0U) {
+      yield = pdFALSE;
+
+      (void)xTaskNotifyIndexedFromISR (hTask, CMSIS_TASK_NOTIFY_INDEX, flags, eSetBits, &yield);
+      (void)xTaskNotifyAndQueryIndexedFromISR (hTask, CMSIS_TASK_NOTIFY_INDEX, 0, eNoAction, &rflags, NULL);
+
+      portYIELD_FROM_ISR (yield);
+    }
+    else {
+      (void)xTaskNotifyIndexed (hTask, CMSIS_TASK_NOTIFY_INDEX, flags, eSetBits);
+      (void)xTaskNotifyAndQueryIndexed (hTask, CMSIS_TASK_NOTIFY_INDEX, 0, eNoAction, &rflags);
+    }
+  }
+  /* Return flags after setting */
+  return (rflags);
+}
+
+/*
+  Clear the specified Thread Flags of current running thread.
+*/
+uint32_t osThreadFlagsClear (uint32_t flags) {
+  TaskHandle_t hTask;
+  uint32_t rflags, cflags;
+
+  if (IRQ_Context() != 0U) {
+    rflags = (uint32_t)osErrorISR;
+  }
+  else if ((flags & THREAD_FLAGS_INVALID_BITS) != 0U) {
+    rflags = (uint32_t)osErrorParameter;
+  }
+  else {
+    hTask = xTaskGetCurrentTaskHandle();
+
+    if (xTaskNotifyAndQueryIndexed (hTask, CMSIS_TASK_NOTIFY_INDEX, 0, eNoAction, &cflags) == pdPASS) {
+      rflags = cflags;
+      cflags &= ~flags;
+
+      if (xTaskNotifyIndexed (hTask, CMSIS_TASK_NOTIFY_INDEX, cflags, eSetValueWithOverwrite) != pdPASS) {
+        rflags = (uint32_t)osError;
+      }
+    }
+    else {
+      rflags = (uint32_t)osError;
+    }
+  }
+
+  /* Return flags before clearing */
+  return (rflags);
+}
+
+/*
+  Get the current Thread Flags of current running thread.
+*/
+uint32_t osThreadFlagsGet (void) {
+  TaskHandle_t hTask;
+  uint32_t rflags;
+
+  if (IRQ_Context() != 0U) {
+    rflags = (uint32_t)osErrorISR;
+  }
+  else {
+    hTask = xTaskGetCurrentTaskHandle();
+
+    if (xTaskNotifyAndQueryIndexed (hTask, CMSIS_TASK_NOTIFY_INDEX, 0, eNoAction, &rflags) != pdPASS) {
+      rflags = (uint32_t)osError;
+    }
+  }
+
+  /* Return current flags */
+  return (rflags);
+}
+
+/*
+  Wait for one or more Thread Flags of the current running thread to become signaled.
+*/
+uint32_t osThreadFlagsWait (uint32_t flags, uint32_t options, uint32_t timeout) {
+  uint32_t rflags, nval;
+  uint32_t clear;
+  TickType_t t0, td, tout;
+  BaseType_t rval;
+
+  if (IRQ_Context() != 0U) {
+    rflags = (uint32_t)osErrorISR;
+  }
+  else if ((flags & THREAD_FLAGS_INVALID_BITS) != 0U) {
+    rflags = (uint32_t)osErrorParameter;
+  }
+  else {
+    if ((options & osFlagsNoClear) == osFlagsNoClear) {
+      clear = 0U;
+    } else {
+      clear = flags;
+    }
+
+    rflags = 0U;
+    tout   = timeout;
+
+    t0 = xTaskGetTickCount();
+    do {
+      rval = xTaskNotifyWaitIndexed (CMSIS_TASK_NOTIFY_INDEX, 0, clear, &nval, tout);
+
+      if (rval == pdPASS) {
+        rflags &= flags;
+        rflags |= nval;
+
+        if ((options & osFlagsWaitAll) == osFlagsWaitAll) {
+          if ((flags & rflags) == flags) {
+            break;
+          } else {
+            if (timeout == 0U) {
+              rflags = (uint32_t)osErrorResource;
+              break;
+            }
+          }
+        }
+        else {
+          if ((flags & rflags) != 0) {
+            break;
+          } else {
+            if (timeout == 0U) {
+              rflags = (uint32_t)osErrorResource;
+              break;
+            }
+          }
+        }
+
+        /* Update timeout */
+        td = xTaskGetTickCount() - t0;
+
+        if (td > timeout) {
+          tout  = 0;
+        } else {
+          tout = timeout - td;
+        }
+      }
+      else {
+        if (timeout == 0) {
+          rflags = (uint32_t)osErrorResource;
+        } else {
+          rflags = (uint32_t)osErrorTimeout;
+        }
+      }
+    }
+    while (rval != pdFAIL);
+  }
+
+  /* Return flags before clearing */
+  return (rflags);
+}
+#endif /* (configUSE_OS2_THREAD_FLAGS == 1) */
+
+
+/* ==== Generic Wait Functions ==== */
+
+/*
+  Wait for Timeout (Time Delay).
+*/
+osStatus_t osDelay (uint32_t ticks) {
+  osStatus_t stat;
+
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else {
+    stat = osOK;
+
+    if (ticks != 0U) {
+      vTaskDelay(ticks);
+    }
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+/*
+  Wait until specified time.
+*/
+osStatus_t osDelayUntil (uint32_t ticks) {
+  TickType_t tcnt, delay;
+  osStatus_t stat;
+
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else {
+    stat = osOK;
+    tcnt = xTaskGetTickCount();
+
+    /* Determine remaining number of ticks to delay */
+    delay = (TickType_t)ticks - tcnt;
+
+    /* Check if target tick has not expired */
+    if((delay != 0U) && (0 == (delay >> (8 * sizeof(TickType_t) - 1)))) {
+      if (xTaskDelayUntil (&tcnt, delay) == pdFALSE) {
+        /* Did not delay */
+        stat = osError;
+      }
+    }
+    else
+    {
+      /* No delay or already expired */
+      stat = osErrorParameter;
+    }
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+
+/* ==== Timer Management Functions ==== */
+
+#if (configUSE_OS2_TIMER == 1)
+
+static void TimerCallback (TimerHandle_t hTimer) {
+  TimerCallback_t *callb;
+
+  /* Retrieve pointer to callback function and argument */
+  callb = (TimerCallback_t *)pvTimerGetTimerID (hTimer);
+
+  /* Remove dynamic allocation flag */
+  callb = (TimerCallback_t *)((uint32_t)callb & ~1U);
+
+  if (callb != NULL) {
+    callb->func (callb->arg);
+  }
+}
+
+/*
+  Create and Initialize a timer.
+*/
+osTimerId_t osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr) {
+  const char *name;
+  TimerHandle_t hTimer;
+  TimerCallback_t *callb;
+  UBaseType_t reload;
+  int32_t mem;
+  uint32_t callb_dyn;
+
+  hTimer = NULL;
+
+  if ((IRQ_Context() == 0U) && (func != NULL)) {
+    callb     = NULL;
+    callb_dyn = 0U;
+
+    #if (configSUPPORT_STATIC_ALLOCATION == 1)
+      /* Static memory allocation is available: check if memory for control block */
+      /* is provided and if it also contains space for callback and its argument  */
+      if ((attr != NULL) && (attr->cb_mem != NULL)) {
+        if (attr->cb_size >= (sizeof(StaticTimer_t) + sizeof(TimerCallback_t))) {
+          callb = (TimerCallback_t *)((uint32_t)attr->cb_mem + sizeof(StaticTimer_t));
+        }
+      }
+    #endif
+
+    #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
+      /* Dynamic memory allocation is available: if memory for callback and */
+      /* its argument is not provided, allocate it from dynamic memory pool */
+      if (callb == NULL) {
+        callb = (TimerCallback_t *)pvPortMalloc (sizeof(TimerCallback_t));
+
+        if (callb != NULL) {
+          /* Callback memory was allocated from dynamic pool, set flag */
+          callb_dyn = 1U;
+        }
+      }
+    #endif
+
+    if (callb != NULL) {
+      callb->func = func;
+      callb->arg  = argument;
+
+      if (type == osTimerOnce) {
+        reload = pdFALSE;
+      } else {
+        reload = pdTRUE;
+      }
+
+      mem  = -1;
+      name = NULL;
+
+      if (attr != NULL) {
+        if (attr->name != NULL) {
+          name = attr->name;
+        }
+
+        if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticTimer_t))) {
+          /* The memory for control block is provided, use static object */
+          mem = 1;
+        }
+        else {
+          if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
+            /* Control block will be allocated from the dynamic pool */
+            mem = 0;
+          }
+        }
+      }
+      else {
+        mem = 0;
+      }
+      /* Store callback memory dynamic allocation flag */
+      callb = (TimerCallback_t *)((uint32_t)callb | callb_dyn);
+      /*
+        TimerCallback function is always provided as a callback and is used to call application
+        specified function with its argument both stored in structure callb.
+      */
+      if (mem == 1) {
+        #if (configSUPPORT_STATIC_ALLOCATION == 1)
+          hTimer = xTimerCreateStatic (name, 1, reload, callb, TimerCallback, (StaticTimer_t *)attr->cb_mem);
+        #endif
+      }
+      else {
+        if (mem == 0) {
+          #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
+            hTimer = xTimerCreate (name, 1, reload, callb, TimerCallback);
+          #endif
+        }
+      }
+
+      #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
+      if ((hTimer == NULL) && (callb != NULL) && (callb_dyn == 1U)) {
+        /* Failed to create a timer, release allocated resources */
+        callb = (TimerCallback_t *)((uint32_t)callb & ~1U);
+
+        vPortFree (callb);
+      }
+      #endif
+    }
+  }
+
+  /* Return timer ID */
+  return ((osTimerId_t)hTimer);
+}
+
+/*
+  Get name of a timer.
+*/
+const char *osTimerGetName (osTimerId_t timer_id) {
+  TimerHandle_t hTimer = (TimerHandle_t)timer_id;
+  const char *p;
+
+  if ((IRQ_Context() != 0U) || (hTimer == NULL)) {
+    p = NULL;
+  } else {
+    p = pcTimerGetName (hTimer);
+  }
+
+  /* Return name as null-terminated string */
+  return (p);
+}
+
+/*
+  Start or restart a timer.
+*/
+osStatus_t osTimerStart (osTimerId_t timer_id, uint32_t ticks) {
+  TimerHandle_t hTimer = (TimerHandle_t)timer_id;
+  osStatus_t stat;
+
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else if (hTimer == NULL) {
+    stat = osErrorParameter;
+  }
+  else {
+    if (xTimerChangePeriod (hTimer, ticks, 0) == pdPASS) {
+      stat = osOK;
+    } else {
+      stat = osErrorResource;
+    }
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+/*
+  Stop a timer.
+*/
+osStatus_t osTimerStop (osTimerId_t timer_id) {
+  TimerHandle_t hTimer = (TimerHandle_t)timer_id;
+  osStatus_t stat;
+
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else if (hTimer == NULL) {
+    stat = osErrorParameter;
+  }
+  else {
+    if (xTimerIsTimerActive (hTimer) == pdFALSE) {
+      stat = osErrorResource;
+    }
+    else {
+      if (xTimerStop (hTimer, 0) == pdPASS) {
+        stat = osOK;
+      } else {
+        stat = osError;
+      }
+    }
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+/*
+  Check if a timer is running.
+*/
+uint32_t osTimerIsRunning (osTimerId_t timer_id) {
+  TimerHandle_t hTimer = (TimerHandle_t)timer_id;
+  uint32_t running;
+
+  if ((IRQ_Context() != 0U) || (hTimer == NULL)) {
+    running = 0U;
+  } else {
+    running = (uint32_t)xTimerIsTimerActive (hTimer);
+  }
+
+  /* Return 0: not running, 1: running */
+  return (running);
+}
+
+/*
+  Delete a timer.
+*/
+osStatus_t osTimerDelete (osTimerId_t timer_id) {
+  TimerHandle_t hTimer = (TimerHandle_t)timer_id;
+  osStatus_t stat;
+#ifndef USE_FreeRTOS_HEAP_1
+#if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
+  TimerCallback_t *callb;
+#endif
+
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else if (hTimer == NULL) {
+    stat = osErrorParameter;
+  }
+  else {
+    #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
+    callb = (TimerCallback_t *)pvTimerGetTimerID (hTimer);
+    #endif
+
+    if (xTimerDelete (hTimer, 0) == pdPASS) {
+      #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
+        if ((uint32_t)callb & 1U) {
+          /* Callback memory was allocated from dynamic pool, clear flag */
+          callb = (TimerCallback_t *)((uint32_t)callb & ~1U);
+
+          /* Return allocated memory to dynamic pool */
+          vPortFree (callb);
+        }
+      #endif
+      stat = osOK;
+    } else {
+      stat = osErrorResource;
+    }
+  }
+#else
+  stat = osError;
+#endif
+
+  /* Return execution status */
+  return (stat);
+}
+#endif /* (configUSE_OS2_TIMER == 1) */
+
+
+/* ==== Event Flags Management Functions ==== */
+
+/*
+  Create and Initialize an Event Flags object.
+
+  Limitations:
+  - Event flags are limited to 24 bits.
+*/
+osEventFlagsId_t osEventFlagsNew (const osEventFlagsAttr_t *attr) {
+  EventGroupHandle_t hEventGroup;
+  int32_t mem;
+
+  hEventGroup = NULL;
+
+  if (IRQ_Context() == 0U) {
+    mem = -1;
+
+    if (attr != NULL) {
+      if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticEventGroup_t))) {
+        /* The memory for control block is provided, use static object */
+        mem = 1;
+      }
+      else {
+        if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
+          /* Control block will be allocated from the dynamic pool */
+          mem = 0;
+        }
+      }
+    }
+    else {
+      mem = 0;
+    }
+
+    if (mem == 1) {
+      #if (configSUPPORT_STATIC_ALLOCATION == 1)
+      hEventGroup = xEventGroupCreateStatic (attr->cb_mem);
+      #endif
+    }
+    else {
+      if (mem == 0) {
+        #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
+          hEventGroup = xEventGroupCreate();
+        #endif
+      }
+    }
+  }
+
+  /* Return event flags ID */
+  return ((osEventFlagsId_t)hEventGroup);
+}
+
+/*
+  Set the specified Event Flags.
+
+  Limitations:
+  - Event flags are limited to 24 bits.
+*/
+uint32_t osEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags) {
+  EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
+  uint32_t rflags;
+  BaseType_t yield;
+
+  if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) {
+    rflags = (uint32_t)osErrorParameter;
+  }
+  else if (IRQ_Context() != 0U) {
+  #if (configUSE_OS2_EVENTFLAGS_FROM_ISR == 0)
+    (void)yield;
+    /* Enable timers and xTimerPendFunctionCall function to support osEventFlagsSet from ISR */
+    rflags = (uint32_t)osErrorResource;
+  #else
+    yield = pdFALSE;
+
+    if (xEventGroupSetBitsFromISR (hEventGroup, (EventBits_t)flags, &yield) == pdFAIL) {
+      rflags = (uint32_t)osErrorResource;
+    } else {
+      rflags = flags;
+      portYIELD_FROM_ISR (yield);
+    }
+  #endif
+  }
+  else {
+    rflags = xEventGroupSetBits (hEventGroup, (EventBits_t)flags);
+  }
+
+  /* Return event flags after setting */
+  return (rflags);
+}
+
+/*
+  Clear the specified Event Flags.
+
+  Limitations:
+  - Event flags are limited to 24 bits.
+*/
+uint32_t osEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags) {
+  EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
+  uint32_t rflags;
+
+  if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) {
+    rflags = (uint32_t)osErrorParameter;
+  }
+  else if (IRQ_Context() != 0U) {
+  #if (configUSE_OS2_EVENTFLAGS_FROM_ISR == 0)
+    /* Enable timers and xTimerPendFunctionCall function to support osEventFlagsSet from ISR */
+    rflags = (uint32_t)osErrorResource;
+  #else
+    rflags = xEventGroupGetBitsFromISR (hEventGroup);
+
+    if (xEventGroupClearBitsFromISR (hEventGroup, (EventBits_t)flags) == pdFAIL) {
+      rflags = (uint32_t)osErrorResource;
+    }
+    else {
+      /* xEventGroupClearBitsFromISR only registers clear operation in the timer command queue. */
+      /* Yield is required here otherwise clear operation might not execute in the right order. */
+      /* See https://github.com/FreeRTOS/FreeRTOS-Kernel/issues/93 for more info.               */
+      portYIELD_FROM_ISR (pdTRUE);
+    }
+  #endif
+  }
+  else {
+    rflags = xEventGroupClearBits (hEventGroup, (EventBits_t)flags);
+  }
+
+  /* Return event flags before clearing */
+  return (rflags);
+}
+
+/*
+  Get the current Event Flags.
+
+  Limitations:
+  - Event flags are limited to 24 bits.
+*/
+uint32_t osEventFlagsGet (osEventFlagsId_t ef_id) {
+  EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
+  uint32_t rflags;
+
+  if (ef_id == NULL) {
+    rflags = 0U;
+  }
+  else if (IRQ_Context() != 0U) {
+    rflags = xEventGroupGetBitsFromISR (hEventGroup);
+  }
+  else {
+    rflags = xEventGroupGetBits (hEventGroup);
+  }
+
+  /* Return current event flags */
+  return (rflags);
+}
+
+/*
+  Wait for one or more Event Flags to become signaled.
+
+  Limitations:
+  - Event flags are limited to 24 bits.
+  - osEventFlagsWait cannot be called from an ISR.
+*/
+uint32_t osEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout) {
+  EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
+  BaseType_t wait_all;
+  BaseType_t exit_clr;
+  uint32_t rflags;
+
+  if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) {
+    rflags = (uint32_t)osErrorParameter;
+  }
+  else if (IRQ_Context() != 0U) {
+    rflags = (uint32_t)osErrorISR;
+  }
+  else {
+    if (options & osFlagsWaitAll) {
+      wait_all = pdTRUE;
+    } else {
+      wait_all = pdFAIL;
+    }
+
+    if (options & osFlagsNoClear) {
+      exit_clr = pdFAIL;
+    } else {
+      exit_clr = pdTRUE;
+    }
+
+    rflags = xEventGroupWaitBits (hEventGroup, (EventBits_t)flags, exit_clr, wait_all, (TickType_t)timeout);
+
+    if (options & osFlagsWaitAll) {
+      if ((flags & rflags) != flags) {
+        if (timeout > 0U) {
+          rflags = (uint32_t)osErrorTimeout;
+        } else {
+          rflags = (uint32_t)osErrorResource;
+        }
+      }
+    }
+    else {
+      if ((flags & rflags) == 0U) {
+        if (timeout > 0U) {
+          rflags = (uint32_t)osErrorTimeout;
+        } else {
+          rflags = (uint32_t)osErrorResource;
+        }
+      }
+    }
+  }
+
+  /* Return event flags before clearing */
+  return (rflags);
+}
+
+/*
+  Delete an Event Flags object.
+*/
+osStatus_t osEventFlagsDelete (osEventFlagsId_t ef_id) {
+  EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
+  osStatus_t stat;
+
+#ifndef USE_FreeRTOS_HEAP_1
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else if (hEventGroup == NULL) {
+    stat = osErrorParameter;
+  }
+  else {
+    stat = osOK;
+    vEventGroupDelete (hEventGroup);
+  }
+#else
+  stat = osError;
+#endif
+
+  /* Return execution status */
+  return (stat);
+}
+
+
+/* ==== Mutex Management Functions ==== */
+
+#if (configUSE_OS2_MUTEX == 1)
+/*
+  Create and Initialize a Mutex object.
+
+  Limitations:
+  - Priority inherit protocol is used by default, osMutexPrioInherit attribute is ignored.
+  - Robust mutex is not supported, NULL is returned if used.
+*/
+osMutexId_t osMutexNew (const osMutexAttr_t *attr) {
+  SemaphoreHandle_t hMutex;
+  uint32_t type;
+  uint32_t rmtx;
+  int32_t  mem;
+
+  hMutex = NULL;
+
+  if (IRQ_Context() == 0U) {
+    if (attr != NULL) {
+      type = attr->attr_bits;
+    } else {
+      type = 0U;
+    }
+
+    if ((type & osMutexRecursive) == osMutexRecursive) {
+      rmtx = 1U;
+    } else {
+      rmtx = 0U;
+    }
+
+    if ((type & osMutexRobust) != osMutexRobust) {
+      mem = -1;
+
+      if (attr != NULL) {
+        if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) {
+          /* The memory for control block is provided, use static object */
+          mem = 1;
+        }
+        else {
+          if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
+            /* Control block will be allocated from the dynamic pool */
+            mem = 0;
+          }
+        }
+      }
+      else {
+        mem = 0;
+      }
+
+      if (mem == 1) {
+        #if (configSUPPORT_STATIC_ALLOCATION == 1)
+          if (rmtx != 0U) {
+            #if (configUSE_RECURSIVE_MUTEXES == 1)
+            hMutex = xSemaphoreCreateRecursiveMutexStatic (attr->cb_mem);
+            #endif
+          }
+          else {
+            hMutex = xSemaphoreCreateMutexStatic (attr->cb_mem);
+          }
+        #endif
+      }
+      else {
+        if (mem == 0) {
+          #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
+            if (rmtx != 0U) {
+              #if (configUSE_RECURSIVE_MUTEXES == 1)
+              hMutex = xSemaphoreCreateRecursiveMutex ();
+              #endif
+            } else {
+              hMutex = xSemaphoreCreateMutex ();
+            }
+          #endif
+        }
+      }
+
+      #if (configQUEUE_REGISTRY_SIZE > 0)
+      if (hMutex != NULL) {
+        if ((attr != NULL) && (attr->name != NULL)) {
+          /* Only non-NULL name objects are added to the Queue Registry */
+          vQueueAddToRegistry (hMutex, attr->name);
+        }
+      }
+      #endif
+
+      if ((hMutex != NULL) && (rmtx != 0U)) {
+        /* Set LSB as 'recursive mutex flag' */
+        hMutex = (SemaphoreHandle_t)((uint32_t)hMutex | 1U);
+      }
+    }
+  }
+
+  /* Return mutex ID */
+  return ((osMutexId_t)hMutex);
+}
+
+/*
+  Acquire a Mutex or timeout if it is locked.
+*/
+osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) {
+  SemaphoreHandle_t hMutex;
+  osStatus_t stat;
+  uint32_t rmtx;
+
+  hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
+
+  /* Extract recursive mutex flag */
+  rmtx = (uint32_t)mutex_id & 1U;
+
+  stat = osOK;
+
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else if (hMutex == NULL) {
+    stat = osErrorParameter;
+  }
+  else {
+    if (rmtx != 0U) {
+      #if (configUSE_RECURSIVE_MUTEXES == 1)
+      if (xSemaphoreTakeRecursive (hMutex, timeout) != pdPASS) {
+        if (timeout != 0U) {
+          stat = osErrorTimeout;
+        } else {
+          stat = osErrorResource;
+        }
+      }
+      #endif
+    }
+    else {
+      if (xSemaphoreTake (hMutex, timeout) != pdPASS) {
+        if (timeout != 0U) {
+          stat = osErrorTimeout;
+        } else {
+          stat = osErrorResource;
+        }
+      }
+    }
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+/*
+  Release a Mutex that was acquired by osMutexAcquire.
+*/
+osStatus_t osMutexRelease (osMutexId_t mutex_id) {
+  SemaphoreHandle_t hMutex;
+  osStatus_t stat;
+  uint32_t rmtx;
+
+  hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
+
+  /* Extract recursive mutex flag */
+  rmtx = (uint32_t)mutex_id & 1U;
+
+  stat = osOK;
+
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else if (hMutex == NULL) {
+    stat = osErrorParameter;
+  }
+  else {
+    if (rmtx != 0U) {
+      #if (configUSE_RECURSIVE_MUTEXES == 1)
+      if (xSemaphoreGiveRecursive (hMutex) != pdPASS) {
+        stat = osErrorResource;
+      }
+      #endif
+    }
+    else {
+      if (xSemaphoreGive (hMutex) != pdPASS) {
+        stat = osErrorResource;
+      }
+    }
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+/*
+  Get Thread which owns a Mutex object.
+*/
+osThreadId_t osMutexGetOwner (osMutexId_t mutex_id) {
+  SemaphoreHandle_t hMutex;
+  osThreadId_t owner;
+
+  hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
+
+  if ((IRQ_Context() != 0U) || (hMutex == NULL)) {
+    owner = NULL;
+  } else {
+    owner = (osThreadId_t)xSemaphoreGetMutexHolder (hMutex);
+  }
+
+  /* Return owner thread ID */
+  return (owner);
+}
+
+/*
+  Delete a Mutex object.
+*/
+osStatus_t osMutexDelete (osMutexId_t mutex_id) {
+  osStatus_t stat;
+#ifndef USE_FreeRTOS_HEAP_1
+  SemaphoreHandle_t hMutex;
+
+  hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
+
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else if (hMutex == NULL) {
+    stat = osErrorParameter;
+  }
+  else {
+    #if (configQUEUE_REGISTRY_SIZE > 0)
+    vQueueUnregisterQueue (hMutex);
+    #endif
+    stat = osOK;
+    vSemaphoreDelete (hMutex);
+  }
+#else
+  stat = osError;
+#endif
+
+  /* Return execution status */
+  return (stat);
+}
+#endif /* (configUSE_OS2_MUTEX == 1) */
+
+
+/* ==== Semaphore Management Functions ==== */
+
+/*
+  Create and Initialize a Semaphore object.
+*/
+osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) {
+  SemaphoreHandle_t hSemaphore;
+  int32_t mem;
+
+  hSemaphore = NULL;
+
+  if ((IRQ_Context() == 0U) && (max_count > 0U) && (initial_count <= max_count)) {
+    mem = -1;
+
+    if (attr != NULL) {
+      if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) {
+        /* The memory for control block is provided, use static object */
+        mem = 1;
+      }
+      else {
+        if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
+          /* Control block will be allocated from the dynamic pool */
+          mem = 0;
+        }
+      }
+    }
+    else {
+      mem = 0;
+    }
+
+    if (mem != -1) {
+      if (max_count == 1U) {
+        if (mem == 1) {
+          #if (configSUPPORT_STATIC_ALLOCATION == 1)
+            hSemaphore = xSemaphoreCreateBinaryStatic ((StaticSemaphore_t *)attr->cb_mem);
+          #endif
+        }
+        else {
+          #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
+            hSemaphore = xSemaphoreCreateBinary();
+          #endif
+        }
+
+        if ((hSemaphore != NULL) && (initial_count != 0U)) {
+          if (xSemaphoreGive (hSemaphore) != pdPASS) {
+            vSemaphoreDelete (hSemaphore);
+            hSemaphore = NULL;
+          }
+        }
+      }
+      else {
+        if (mem == 1) {
+          #if (configSUPPORT_STATIC_ALLOCATION == 1)
+            hSemaphore = xSemaphoreCreateCountingStatic (max_count, initial_count, (StaticSemaphore_t *)attr->cb_mem);
+          #endif
+        }
+        else {
+          #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
+            hSemaphore = xSemaphoreCreateCounting (max_count, initial_count);
+          #endif
+        }
+      }
+      
+      #if (configQUEUE_REGISTRY_SIZE > 0)
+      if (hSemaphore != NULL) {
+        if ((attr != NULL) && (attr->name != NULL)) {
+          /* Only non-NULL name objects are added to the Queue Registry */
+          vQueueAddToRegistry (hSemaphore, attr->name);
+        }
+      }
+      #endif
+    }
+  }
+
+  /* Return semaphore ID */
+  return ((osSemaphoreId_t)hSemaphore);
+}
+
+/*
+  Acquire a Semaphore token or timeout if no tokens are available.
+*/
+osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) {
+  SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
+  osStatus_t stat;
+  BaseType_t yield;
+
+  stat = osOK;
+
+  if (hSemaphore == NULL) {
+    stat = osErrorParameter;
+  }
+  else if (IRQ_Context() != 0U) {
+    if (timeout != 0U) {
+      stat = osErrorParameter;
+    }
+    else {
+      yield = pdFALSE;
+
+      if (xSemaphoreTakeFromISR (hSemaphore, &yield) != pdPASS) {
+        stat = osErrorResource;
+      } else {
+        portYIELD_FROM_ISR (yield);
+      }
+    }
+  }
+  else {
+    if (xSemaphoreTake (hSemaphore, (TickType_t)timeout) != pdPASS) {
+      if (timeout != 0U) {
+        stat = osErrorTimeout;
+      } else {
+        stat = osErrorResource;
+      }
+    }
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+/*
+  Release a Semaphore token up to the initial maximum count.
+*/
+osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id) {
+  SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
+  osStatus_t stat;
+  BaseType_t yield;
+
+  stat = osOK;
+
+  if (hSemaphore == NULL) {
+    stat = osErrorParameter;
+  }
+  else if (IRQ_Context() != 0U) {
+    yield = pdFALSE;
+
+    if (xSemaphoreGiveFromISR (hSemaphore, &yield) != pdTRUE) {
+      stat = osErrorResource;
+    } else {
+      portYIELD_FROM_ISR (yield);
+    }
+  }
+  else {
+    if (xSemaphoreGive (hSemaphore) != pdPASS) {
+      stat = osErrorResource;
+    }
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+/*
+  Get current Semaphore token count.
+*/
+uint32_t osSemaphoreGetCount (osSemaphoreId_t semaphore_id) {
+  SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
+  uint32_t count;
+
+  if (hSemaphore == NULL) {
+    count = 0U;
+  }
+  else if (IRQ_Context() != 0U) {
+    count = (uint32_t)uxSemaphoreGetCountFromISR (hSemaphore);
+  } else {
+    count = (uint32_t)uxSemaphoreGetCount (hSemaphore);
+  }
+
+  /* Return number of tokens */
+  return (count);
+}
+
+/*
+  Delete a Semaphore object.
+*/
+osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id) {
+  SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
+  osStatus_t stat;
+
+#ifndef USE_FreeRTOS_HEAP_1
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else if (hSemaphore == NULL) {
+    stat = osErrorParameter;
+  }
+  else {
+    #if (configQUEUE_REGISTRY_SIZE > 0)
+    vQueueUnregisterQueue (hSemaphore);
+    #endif
+
+    stat = osOK;
+    vSemaphoreDelete (hSemaphore);
+  }
+#else
+  stat = osError;
+#endif
+
+  /* Return execution status */
+  return (stat);
+}
+
+
+/* ==== Message Queue Management Functions ==== */
+
+/*
+  Create and Initialize a Message Queue object.
+
+  Limitations:
+  - The memory for control block and and message data must be provided in the
+    osThreadAttr_t structure in order to allocate object statically.
+*/
+osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr) {
+  QueueHandle_t hQueue;
+  int32_t mem;
+
+  hQueue = NULL;
+
+  if ((IRQ_Context() == 0U) && (msg_count > 0U) && (msg_size > 0U)) {
+    mem = -1;
+
+    if (attr != NULL) {
+      if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticQueue_t)) &&
+          (attr->mq_mem != NULL) && (attr->mq_size >= (msg_count * msg_size))) {
+        /* The memory for control block and message data is provided, use static object */
+        mem = 1;
+      }
+      else {
+        if ((attr->cb_mem == NULL) && (attr->cb_size == 0U) &&
+            (attr->mq_mem == NULL) && (attr->mq_size == 0U)) {
+          /* Control block will be allocated from the dynamic pool */
+          mem = 0;
+        }
+      }
+    }
+    else {
+      mem = 0;
+    }
+
+    if (mem == 1) {
+      #if (configSUPPORT_STATIC_ALLOCATION == 1)
+        hQueue = xQueueCreateStatic (msg_count, msg_size, attr->mq_mem, attr->cb_mem);
+      #endif
+    }
+    else {
+      if (mem == 0) {
+        #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
+          hQueue = xQueueCreate (msg_count, msg_size);
+        #endif
+      }
+    }
+
+    #if (configQUEUE_REGISTRY_SIZE > 0)
+    if (hQueue != NULL) {
+      if ((attr != NULL) && (attr->name != NULL)) {
+        /* Only non-NULL name objects are added to the Queue Registry */
+        vQueueAddToRegistry (hQueue, attr->name);
+      }
+    }
+    #endif
+
+  }
+
+  /* Return message queue ID */
+  return ((osMessageQueueId_t)hQueue);
+}
+
+/*
+  Put a Message into a Queue or timeout if Queue is full.
+
+  Limitations:
+  - Message priority is ignored
+*/
+osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) {
+  QueueHandle_t hQueue = (QueueHandle_t)mq_id;
+  osStatus_t stat;
+  BaseType_t yield;
+
+  (void)msg_prio; /* Message priority is ignored */
+
+  stat = osOK;
+
+  if (IRQ_Context() != 0U) {
+    if ((hQueue == NULL) || (msg_ptr == NULL) || (timeout != 0U)) {
+      stat = osErrorParameter;
+    }
+    else {
+      yield = pdFALSE;
+
+      if (xQueueSendToBackFromISR (hQueue, msg_ptr, &yield) != pdTRUE) {
+        stat = osErrorResource;
+      } else {
+        portYIELD_FROM_ISR (yield);
+      }
+    }
+  }
+  else {
+    if ((hQueue == NULL) || (msg_ptr == NULL)) {
+      stat = osErrorParameter;
+    }
+    else {
+      if (xQueueSendToBack (hQueue, msg_ptr, (TickType_t)timeout) != pdPASS) {
+        if (timeout != 0U) {
+          stat = osErrorTimeout;
+        } else {
+          stat = osErrorResource;
+        }
+      }
+    }
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+/*
+  Get a Message from a Queue or timeout if Queue is empty.
+
+  Limitations:
+  - Message priority is ignored
+*/
+osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
+  QueueHandle_t hQueue = (QueueHandle_t)mq_id;
+  osStatus_t stat;
+  BaseType_t yield;
+
+  (void)msg_prio; /* Message priority is ignored */
+
+  stat = osOK;
+
+  if (IRQ_Context() != 0U) {
+    if ((hQueue == NULL) || (msg_ptr == NULL) || (timeout != 0U)) {
+      stat = osErrorParameter;
+    }
+    else {
+      yield = pdFALSE;
+
+      if (xQueueReceiveFromISR (hQueue, msg_ptr, &yield) != pdPASS) {
+        stat = osErrorResource;
+      } else {
+        portYIELD_FROM_ISR (yield);
+      }
+    }
+  }
+  else {
+    if ((hQueue == NULL) || (msg_ptr == NULL)) {
+      stat = osErrorParameter;
+    }
+    else {
+      if (xQueueReceive (hQueue, msg_ptr, (TickType_t)timeout) != pdPASS) {
+        if (timeout != 0U) {
+          stat = osErrorTimeout;
+        } else {
+          stat = osErrorResource;
+        }
+      }
+    }
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+/*
+  Get maximum number of messages in a Message Queue.
+*/
+uint32_t osMessageQueueGetCapacity (osMessageQueueId_t mq_id) {
+  StaticQueue_t *mq = (StaticQueue_t *)mq_id;
+  uint32_t capacity;
+
+  if (mq == NULL) {
+    capacity = 0U;
+  } else {
+    /* capacity = pxQueue->uxLength */
+    capacity = mq->uxDummy4[1];
+  }
+
+  /* Return maximum number of messages */
+  return (capacity);
+}
+
+/*
+  Get maximum message size in a Message Queue.
+*/
+uint32_t osMessageQueueGetMsgSize (osMessageQueueId_t mq_id) {
+  StaticQueue_t *mq = (StaticQueue_t *)mq_id;
+  uint32_t size;
+
+  if (mq == NULL) {
+    size = 0U;
+  } else {
+    /* size = pxQueue->uxItemSize */
+    size = mq->uxDummy4[2];
+  }
+
+  /* Return maximum message size */
+  return (size);
+}
+
+/*
+  Get number of queued messages in a Message Queue.
+*/
+uint32_t osMessageQueueGetCount (osMessageQueueId_t mq_id) {
+  QueueHandle_t hQueue = (QueueHandle_t)mq_id;
+  UBaseType_t count;
+
+  if (hQueue == NULL) {
+    count = 0U;
+  }
+  else if (IRQ_Context() != 0U) {
+    count = uxQueueMessagesWaitingFromISR (hQueue);
+  }
+  else {
+    count = uxQueueMessagesWaiting (hQueue);
+  }
+
+  /* Return number of queued messages */
+  return ((uint32_t)count);
+}
+
+/*
+  Get number of available slots for messages in a Message Queue.
+*/
+uint32_t osMessageQueueGetSpace (osMessageQueueId_t mq_id) {
+  StaticQueue_t *mq = (StaticQueue_t *)mq_id;
+  uint32_t space;
+  uint32_t isrm;
+
+  if (mq == NULL) {
+    space = 0U;
+  }
+  else if (IRQ_Context() != 0U) {
+    isrm = taskENTER_CRITICAL_FROM_ISR();
+
+    /* space = pxQueue->uxLength - pxQueue->uxMessagesWaiting; */
+    space = mq->uxDummy4[1] - mq->uxDummy4[0];
+
+    taskEXIT_CRITICAL_FROM_ISR(isrm);
+  }
+  else {
+    space = (uint32_t)uxQueueSpacesAvailable ((QueueHandle_t)mq);
+  }
+
+  /* Return number of available slots */
+  return (space);
+}
+
+/*
+  Reset a Message Queue to initial empty state.
+*/
+osStatus_t osMessageQueueReset (osMessageQueueId_t mq_id) {
+  QueueHandle_t hQueue = (QueueHandle_t)mq_id;
+  osStatus_t stat;
+
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else if (hQueue == NULL) {
+    stat = osErrorParameter;
+  }
+  else {
+    stat = osOK;
+    (void)xQueueReset (hQueue);
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+/*
+  Delete a Message Queue object.
+*/
+osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id) {
+  QueueHandle_t hQueue = (QueueHandle_t)mq_id;
+  osStatus_t stat;
+
+#ifndef USE_FreeRTOS_HEAP_1
+  if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else if (hQueue == NULL) {
+    stat = osErrorParameter;
+  }
+  else {
+    #if (configQUEUE_REGISTRY_SIZE > 0)
+    vQueueUnregisterQueue (hQueue);
+    #endif
+
+    stat = osOK;
+    vQueueDelete (hQueue);
+  }
+#else
+  stat = osError;
+#endif
+
+  /* Return execution status */
+  return (stat);
+}
+
+
+/* ==== Memory Pool Management Functions ==== */
+
+#ifdef FREERTOS_MPOOL_H_
+/* Static memory pool functions */
+static void  FreeBlock   (MemPool_t *mp, void *block);
+static void *AllocBlock  (MemPool_t *mp);
+static void *CreateBlock (MemPool_t *mp);
+
+/*
+  Create and Initialize a Memory Pool object.
+*/
+osMemoryPoolId_t osMemoryPoolNew (uint32_t block_count, uint32_t block_size, const osMemoryPoolAttr_t *attr) {
+  MemPool_t *mp;
+  const char *name;
+  int32_t mem_cb, mem_mp;
+  uint32_t sz;
+
+  if (IRQ_Context() != 0U) {
+    mp = NULL;
+  }
+  else if ((block_count == 0U) || (block_size == 0U)) {
+    mp = NULL;
+  }
+  else {
+    mp = NULL;
+    sz = MEMPOOL_ARR_SIZE (block_count, block_size);
+
+    name = NULL;
+    mem_cb = -1;
+    mem_mp = -1;
+
+    if (attr != NULL) {
+      if (attr->name != NULL) {
+        name = attr->name;
+      }
+
+      if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(MemPool_t))) {
+        /* Static control block is provided */
+        mem_cb = 1;
+      }
+      else if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
+        /* Allocate control block memory on heap */
+        mem_cb = 0;
+      }
+
+      if ((attr->mp_mem == NULL) && (attr->mp_size == 0U)) {
+        /* Allocate memory array on heap */
+          mem_mp = 0;
+      }
+      else {
+        if (attr->mp_mem != NULL) {
+          /* Check if array is 4-byte aligned */
+          if (((uint32_t)attr->mp_mem & 3U) == 0U) {
+            /* Check if array big enough */
+            if (attr->mp_size >= sz) {
+              /* Static memory pool array is provided */
+              mem_mp = 1;
+            }
+          }
+        }
+      }
+    }
+    else {
+      /* Attributes not provided, allocate memory on heap */
+      mem_cb = 0;
+      mem_mp = 0;
+    }
+
+    if (mem_cb == 0) {
+      mp = pvPortMalloc (sizeof(MemPool_t));
+    } else {
+      mp = attr->cb_mem;
+    }
+
+    if (mp != NULL) {
+      /* Create a semaphore (max count == initial count == block_count) */
+      #if (configSUPPORT_STATIC_ALLOCATION == 1)
+        mp->sem = xSemaphoreCreateCountingStatic (block_count, block_count, &mp->mem_sem);
+      #elif (configSUPPORT_DYNAMIC_ALLOCATION == 1)
+        mp->sem = xSemaphoreCreateCounting (block_count, block_count);
+      #else
+        mp->sem = NULL;
+      #endif
+
+      if (mp->sem != NULL) {
+        /* Setup memory array */
+        if (mem_mp == 0) {
+          mp->mem_arr = pvPortMalloc (sz);
+        } else {
+          mp->mem_arr = attr->mp_mem;
+        }
+      }
+    }
+
+    if ((mp != NULL) && (mp->mem_arr != NULL)) {
+      /* Memory pool can be created */
+      mp->head    = NULL;
+      mp->mem_sz  = sz;
+      mp->name    = name;
+      mp->bl_sz   = block_size;
+      mp->bl_cnt  = block_count;
+      mp->n       = 0U;
+
+      /* Set heap allocated memory flags */
+      mp->status = MPOOL_STATUS;
+
+      if (mem_cb == 0) {
+        /* Control block on heap */
+        mp->status |= 1U;
+      }
+      if (mem_mp == 0) {
+        /* Memory array on heap */
+        mp->status |= 2U;
+      }
+    }
+    else {
+      /* Memory pool cannot be created, release allocated resources */
+      if ((mem_cb == 0) && (mp != NULL)) {
+        /* Free control block memory */
+        vPortFree (mp);
+      }
+      mp = NULL;
+    }
+  }
+
+  /* Return memory pool ID */
+  return (mp);
+}
+
+/*
+  Get name of a Memory Pool object.
+*/
+const char *osMemoryPoolGetName (osMemoryPoolId_t mp_id) {
+  MemPool_t *mp = (osMemoryPoolId_t)mp_id;
+  const char *p;
+
+  if (IRQ_Context() != 0U) {
+    p = NULL;
+  }
+  else if (mp_id == NULL) {
+    p = NULL;
+  }
+  else {
+    p = mp->name;
+  }
+
+  /* Return name as null-terminated string */
+  return (p);
+}
+
+/*
+  Allocate a memory block from a Memory Pool.
+*/
+void *osMemoryPoolAlloc (osMemoryPoolId_t mp_id, uint32_t timeout) {
+  MemPool_t *mp;
+  void *block;
+  uint32_t isrm;
+
+  if (mp_id == NULL) {
+    /* Invalid input parameters */
+    block = NULL;
+  }
+  else {
+    block = NULL;
+
+    mp = (MemPool_t *)mp_id;
+
+    if ((mp->status & MPOOL_STATUS) == MPOOL_STATUS) {
+      if (IRQ_Context() != 0U) {
+        if (timeout == 0U) {
+          if (xSemaphoreTakeFromISR (mp->sem, NULL) == pdTRUE) {
+            if ((mp->status & MPOOL_STATUS) == MPOOL_STATUS) {
+              isrm  = taskENTER_CRITICAL_FROM_ISR();
+
+              /* Get a block from the free-list */
+              block = AllocBlock(mp);
+
+              if (block == NULL) {
+                /* List of free blocks is empty, 'create' new block */
+                block = CreateBlock(mp);
+              }
+
+              taskEXIT_CRITICAL_FROM_ISR(isrm);
+            }
+          }
+        }
+      }
+      else {
+        if (xSemaphoreTake (mp->sem, (TickType_t)timeout) == pdTRUE) {
+          if ((mp->status & MPOOL_STATUS) == MPOOL_STATUS) {
+            taskENTER_CRITICAL();
+
+            /* Get a block from the free-list */
+            block = AllocBlock(mp);
+
+            if (block == NULL) {
+              /* List of free blocks is empty, 'create' new block */
+              block = CreateBlock(mp);
+            }
+
+            taskEXIT_CRITICAL();
+          }
+        }
+      }
+    }
+  }
+
+  /* Return memory block address */
+  return (block);
+}
+
+/*
+  Return an allocated memory block back to a Memory Pool.
+*/
+osStatus_t osMemoryPoolFree (osMemoryPoolId_t mp_id, void *block) {
+  MemPool_t *mp;
+  osStatus_t stat;
+  uint32_t isrm;
+  BaseType_t yield;
+
+  if ((mp_id == NULL) || (block == NULL)) {
+    /* Invalid input parameters */
+    stat = osErrorParameter;
+  }
+  else {
+    mp = (MemPool_t *)mp_id;
+
+    if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) {
+      /* Invalid object status */
+      stat = osErrorResource;
+    }
+    else if ((block < (void *)&mp->mem_arr[0]) || (block > (void*)&mp->mem_arr[mp->mem_sz-1])) {
+      /* Block pointer outside of memory array area */
+      stat = osErrorParameter;
+    }
+    else {
+      stat = osOK;
+
+      if (IRQ_Context() != 0U) {
+        if (uxSemaphoreGetCountFromISR (mp->sem) == mp->bl_cnt) {
+          stat = osErrorResource;
+        }
+        else {
+          isrm = taskENTER_CRITICAL_FROM_ISR();
+
+          /* Add block to the list of free blocks */
+          FreeBlock(mp, block);
+
+          taskEXIT_CRITICAL_FROM_ISR(isrm);
+
+          yield = pdFALSE;
+          xSemaphoreGiveFromISR (mp->sem, &yield);
+          portYIELD_FROM_ISR (yield);
+        }
+      }
+      else {
+        if (uxSemaphoreGetCount (mp->sem) == mp->bl_cnt) {
+          stat = osErrorResource;
+        }
+        else {
+          taskENTER_CRITICAL();
+
+          /* Add block to the list of free blocks */
+          FreeBlock(mp, block);
+
+          taskEXIT_CRITICAL();
+
+          xSemaphoreGive (mp->sem);
+        }
+      }
+    }
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+/*
+  Get maximum number of memory blocks in a Memory Pool.
+*/
+uint32_t osMemoryPoolGetCapacity (osMemoryPoolId_t mp_id) {
+  MemPool_t *mp;
+  uint32_t  n;
+
+  if (mp_id == NULL) {
+    /* Invalid input parameters */
+    n = 0U;
+  }
+  else {
+    mp = (MemPool_t *)mp_id;
+
+    if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) {
+      /* Invalid object status */
+      n = 0U;
+    }
+    else {
+      n = mp->bl_cnt;
+    }
+  }
+
+  /* Return maximum number of memory blocks */
+  return (n);
+}
+
+/*
+  Get memory block size in a Memory Pool.
+*/
+uint32_t osMemoryPoolGetBlockSize (osMemoryPoolId_t mp_id) {
+  MemPool_t *mp;
+  uint32_t  sz;
+
+  if (mp_id == NULL) {
+    /* Invalid input parameters */
+    sz = 0U;
+  }
+  else {
+    mp = (MemPool_t *)mp_id;
+
+    if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) {
+      /* Invalid object status */
+      sz = 0U;
+    }
+    else {
+      sz = mp->bl_sz;
+    }
+  }
+
+  /* Return memory block size in bytes */
+  return (sz);
+}
+
+/*
+  Get number of memory blocks used in a Memory Pool.
+*/
+uint32_t osMemoryPoolGetCount (osMemoryPoolId_t mp_id) {
+  MemPool_t *mp;
+  uint32_t  n;
+
+  if (mp_id == NULL) {
+    /* Invalid input parameters */
+    n = 0U;
+  }
+  else {
+    mp = (MemPool_t *)mp_id;
+
+    if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) {
+      /* Invalid object status */
+      n = 0U;
+    }
+    else {
+      if (IRQ_Context() != 0U) {
+        n = uxSemaphoreGetCountFromISR (mp->sem);
+      } else {
+        n = uxSemaphoreGetCount        (mp->sem);
+      }
+
+      n = mp->bl_cnt - n;
+    }
+  }
+
+  /* Return number of memory blocks used */
+  return (n);
+}
+
+/*
+  Get number of memory blocks available in a Memory Pool.
+*/
+uint32_t osMemoryPoolGetSpace (osMemoryPoolId_t mp_id) {
+  MemPool_t *mp;
+  uint32_t  n;
+
+  if (mp_id == NULL) {
+    /* Invalid input parameters */
+    n = 0U;
+  }
+  else {
+    mp = (MemPool_t *)mp_id;
+
+    if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) {
+      /* Invalid object status */
+      n = 0U;
+    }
+    else {
+      if (IRQ_Context() != 0U) {
+        n = uxSemaphoreGetCountFromISR (mp->sem);
+      } else {
+        n = uxSemaphoreGetCount        (mp->sem);
+      }
+    }
+  }
+
+  /* Return number of memory blocks available */
+  return (n);
+}
+
+/*
+  Delete a Memory Pool object.
+*/
+osStatus_t osMemoryPoolDelete (osMemoryPoolId_t mp_id) {
+  MemPool_t *mp;
+  osStatus_t stat;
+
+  if (mp_id == NULL) {
+    /* Invalid input parameters */
+    stat = osErrorParameter;
+  }
+  else if (IRQ_Context() != 0U) {
+    stat = osErrorISR;
+  }
+  else {
+    mp = (MemPool_t *)mp_id;
+
+    taskENTER_CRITICAL();
+
+    /* Invalidate control block status */
+    mp->status  = mp->status & 3U;
+
+    /* Wake-up tasks waiting for pool semaphore */
+    while (xSemaphoreGive (mp->sem) == pdTRUE);
+
+    mp->head    = NULL;
+    mp->bl_sz   = 0U;
+    mp->bl_cnt  = 0U;
+
+    if ((mp->status & 2U) != 0U) {
+      /* Memory pool array allocated on heap */
+      vPortFree (mp->mem_arr);
+    }
+    if ((mp->status & 1U) != 0U) {
+      /* Memory pool control block allocated on heap */
+      vPortFree (mp);
+    }
+
+    taskEXIT_CRITICAL();
+
+    stat = osOK;
+  }
+
+  /* Return execution status */
+  return (stat);
+}
+
+/*
+  Create new block given according to the current block index.
+*/
+static void *CreateBlock (MemPool_t *mp) {
+  MemPoolBlock_t *p = NULL;
+
+  if (mp->n < mp->bl_cnt) {
+    /* Unallocated blocks exist, set pointer to new block */
+    p = (void *)(mp->mem_arr + (mp->bl_sz * mp->n));
+
+    /* Increment block index */
+    mp->n += 1U;
+  }
+
+  return (p);
+}
+
+/*
+  Allocate a block by reading the list of free blocks.
+*/
+static void *AllocBlock (MemPool_t *mp) {
+  MemPoolBlock_t *p = NULL;
+
+  if (mp->head != NULL) {
+    /* List of free block exists, get head block */
+    p = mp->head;
+
+    /* Head block is now next on the list */
+    mp->head = p->next;
+  }
+
+  return (p);
+}
+
+/*
+  Free block by putting it to the list of free blocks.
+*/
+static void FreeBlock (MemPool_t *mp, void *block) {
+  MemPoolBlock_t *p = block;
+
+  /* Store current head into block memory space */
+  p->next = mp->head;
+
+  /* Store current block as new head */
+  mp->head = p;
+}
+#endif /* FREERTOS_MPOOL_H_ */
+/*---------------------------------------------------------------------------*/
+
+/* Callback function prototypes */
+extern void vApplicationIdleHook (void);
+extern void vApplicationMallocFailedHook (void);
+extern void vApplicationDaemonTaskStartupHook (void);
+
+/**
+  Dummy implementation of the callback function vApplicationIdleHook().
+*/
+#if (configUSE_IDLE_HOOK == 1)
+__WEAK void vApplicationIdleHook (void){}
+#endif
+
+/**
+  Dummy implementation of the callback function vApplicationTickHook().
+*/
+#if (configUSE_TICK_HOOK == 1)
+ __WEAK void vApplicationTickHook (void){}
+#endif
+
+/**
+  Dummy implementation of the callback function vApplicationMallocFailedHook().
+*/
+#if (configUSE_MALLOC_FAILED_HOOK == 1)
+__WEAK void vApplicationMallocFailedHook (void) {
+  /* Assert when malloc failed hook is enabled but no application defined function exists */
+  configASSERT(0);
+}
+#endif
+
+/**
+  Dummy implementation of the callback function vApplicationDaemonTaskStartupHook().
+*/
+#if (configUSE_DAEMON_TASK_STARTUP_HOOK == 1)
+__WEAK void vApplicationDaemonTaskStartupHook (void){}
+#endif
+
+/**
+  Dummy implementation of the callback function vApplicationStackOverflowHook().
+*/
+#if (configCHECK_FOR_STACK_OVERFLOW > 0)
+__WEAK void vApplicationStackOverflowHook (TaskHandle_t xTask, char *pcTaskName) {
+  (void)xTask;
+  (void)pcTaskName;
+
+  /* Assert when stack overflow is enabled but no application defined function exists */
+  configASSERT(0);
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+#if (configSUPPORT_STATIC_ALLOCATION == 1)
+/*
+  vApplicationGetIdleTaskMemory gets called when configSUPPORT_STATIC_ALLOCATION
+  equals to 1 and is required for static memory allocation support.
+*/
+__WEAK void vApplicationGetIdleTaskMemory (StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) {
+  /* Idle task control block and stack */
+  static StaticTask_t Idle_TCB;
+  static StackType_t  Idle_Stack[configMINIMAL_STACK_SIZE];
+
+  *ppxIdleTaskTCBBuffer   = &Idle_TCB;
+  *ppxIdleTaskStackBuffer = &Idle_Stack[0];
+  *pulIdleTaskStackSize   = (uint32_t)configMINIMAL_STACK_SIZE;
+}
+
+/*
+  vApplicationGetTimerTaskMemory gets called when configSUPPORT_STATIC_ALLOCATION
+  equals to 1 and is required for static memory allocation support.
+*/
+__WEAK void vApplicationGetTimerTaskMemory (StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize) {
+  /* Timer task control block and stack */
+  static StaticTask_t Timer_TCB;
+  static StackType_t  Timer_Stack[configTIMER_TASK_STACK_DEPTH];
+
+  *ppxTimerTaskTCBBuffer   = &Timer_TCB;
+  *ppxTimerTaskStackBuffer = &Timer_Stack[0];
+  *pulTimerTaskStackSize   = (uint32_t)configTIMER_TASK_STACK_DEPTH;
+}
+#endif

+ 756 - 0
lib/FreeRTOS-glue/cmsis_os2.h

@@ -0,0 +1,756 @@
+/*
+ * Copyright (c) 2013-2020 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----------------------------------------------------------------------
+ *
+ * $Date:        12. June 2020
+ * $Revision:    V2.1.3
+ *
+ * Project:      CMSIS-RTOS2 API
+ * Title:        cmsis_os2.h header file
+ *
+ * Version 2.1.3
+ *    Additional functions allowed to be called from Interrupt Service Routines:
+ *    - osThreadGetId
+ * Version 2.1.2
+ *    Additional functions allowed to be called from Interrupt Service Routines:
+ *    - osKernelGetInfo, osKernelGetState
+ * Version 2.1.1
+ *    Additional functions allowed to be called from Interrupt Service Routines:
+ *    - osKernelGetTickCount, osKernelGetTickFreq
+ *    Changed Kernel Tick type to uint32_t:
+ *    - updated: osKernelGetTickCount, osDelayUntil
+ * Version 2.1.0
+ *    Support for critical and uncritical sections (nesting safe):
+ *    - updated: osKernelLock, osKernelUnlock
+ *    - added: osKernelRestoreLock
+ *    Updated Thread and Event Flags:
+ *    - changed flags parameter and return type from int32_t to uint32_t
+ * Version 2.0.0
+ *    Initial Release
+ *---------------------------------------------------------------------------*/
+ 
+#ifndef CMSIS_OS2_H_
+#define CMSIS_OS2_H_
+ 
+#ifndef __NO_RETURN
+#if   defined(__CC_ARM)
+#define __NO_RETURN __declspec(noreturn)
+#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
+#define __NO_RETURN __attribute__((__noreturn__))
+#elif defined(__GNUC__)
+#define __NO_RETURN __attribute__((__noreturn__))
+#elif defined(__ICCARM__)
+#define __NO_RETURN __noreturn
+#else
+#define __NO_RETURN
+#endif
+#endif
+ 
+#include <stdint.h>
+#include <stddef.h>
+ 
+#ifdef  __cplusplus
+extern "C"
+{
+#endif
+ 
+ 
+//  ==== Enumerations, structures, defines ====
+ 
+/// Version information.
+typedef struct {
+  uint32_t                       api;   ///< API version (major.minor.rev: mmnnnrrrr dec).
+  uint32_t                    kernel;   ///< Kernel version (major.minor.rev: mmnnnrrrr dec).
+} osVersion_t;
+ 
+/// Kernel state.
+typedef enum {
+  osKernelInactive        =  0,         ///< Inactive.
+  osKernelReady           =  1,         ///< Ready.
+  osKernelRunning         =  2,         ///< Running.
+  osKernelLocked          =  3,         ///< Locked.
+  osKernelSuspended       =  4,         ///< Suspended.
+  osKernelError           = -1,         ///< Error.
+  osKernelReserved        = 0x7FFFFFFF  ///< Prevents enum down-size compiler optimization.
+} osKernelState_t;
+ 
+/// Thread state.
+typedef enum {
+  osThreadInactive        =  0,         ///< Inactive.
+  osThreadReady           =  1,         ///< Ready.
+  osThreadRunning         =  2,         ///< Running.
+  osThreadBlocked         =  3,         ///< Blocked.
+  osThreadTerminated      =  4,         ///< Terminated.
+  osThreadError           = -1,         ///< Error.
+  osThreadReserved        = 0x7FFFFFFF  ///< Prevents enum down-size compiler optimization.
+} osThreadState_t;
+ 
+/// Priority values.
+typedef enum {
+  osPriorityNone          =  0,         ///< No priority (not initialized).
+  osPriorityIdle          =  1,         ///< Reserved for Idle thread.
+  osPriorityLow           =  8,         ///< Priority: low
+  osPriorityLow1          =  8+1,       ///< Priority: low + 1
+  osPriorityLow2          =  8+2,       ///< Priority: low + 2
+  osPriorityLow3          =  8+3,       ///< Priority: low + 3
+  osPriorityLow4          =  8+4,       ///< Priority: low + 4
+  osPriorityLow5          =  8+5,       ///< Priority: low + 5
+  osPriorityLow6          =  8+6,       ///< Priority: low + 6
+  osPriorityLow7          =  8+7,       ///< Priority: low + 7
+  osPriorityBelowNormal   = 16,         ///< Priority: below normal
+  osPriorityBelowNormal1  = 16+1,       ///< Priority: below normal + 1
+  osPriorityBelowNormal2  = 16+2,       ///< Priority: below normal + 2
+  osPriorityBelowNormal3  = 16+3,       ///< Priority: below normal + 3
+  osPriorityBelowNormal4  = 16+4,       ///< Priority: below normal + 4
+  osPriorityBelowNormal5  = 16+5,       ///< Priority: below normal + 5
+  osPriorityBelowNormal6  = 16+6,       ///< Priority: below normal + 6
+  osPriorityBelowNormal7  = 16+7,       ///< Priority: below normal + 7
+  osPriorityNormal        = 24,         ///< Priority: normal
+  osPriorityNormal1       = 24+1,       ///< Priority: normal + 1
+  osPriorityNormal2       = 24+2,       ///< Priority: normal + 2
+  osPriorityNormal3       = 24+3,       ///< Priority: normal + 3
+  osPriorityNormal4       = 24+4,       ///< Priority: normal + 4
+  osPriorityNormal5       = 24+5,       ///< Priority: normal + 5
+  osPriorityNormal6       = 24+6,       ///< Priority: normal + 6
+  osPriorityNormal7       = 24+7,       ///< Priority: normal + 7
+  osPriorityAboveNormal   = 32,         ///< Priority: above normal
+  osPriorityAboveNormal1  = 32+1,       ///< Priority: above normal + 1
+  osPriorityAboveNormal2  = 32+2,       ///< Priority: above normal + 2
+  osPriorityAboveNormal3  = 32+3,       ///< Priority: above normal + 3
+  osPriorityAboveNormal4  = 32+4,       ///< Priority: above normal + 4
+  osPriorityAboveNormal5  = 32+5,       ///< Priority: above normal + 5
+  osPriorityAboveNormal6  = 32+6,       ///< Priority: above normal + 6
+  osPriorityAboveNormal7  = 32+7,       ///< Priority: above normal + 7
+  osPriorityHigh          = 40,         ///< Priority: high
+  osPriorityHigh1         = 40+1,       ///< Priority: high + 1
+  osPriorityHigh2         = 40+2,       ///< Priority: high + 2
+  osPriorityHigh3         = 40+3,       ///< Priority: high + 3
+  osPriorityHigh4         = 40+4,       ///< Priority: high + 4
+  osPriorityHigh5         = 40+5,       ///< Priority: high + 5
+  osPriorityHigh6         = 40+6,       ///< Priority: high + 6
+  osPriorityHigh7         = 40+7,       ///< Priority: high + 7
+  osPriorityRealtime      = 48,         ///< Priority: realtime
+  osPriorityRealtime1     = 48+1,       ///< Priority: realtime + 1
+  osPriorityRealtime2     = 48+2,       ///< Priority: realtime + 2
+  osPriorityRealtime3     = 48+3,       ///< Priority: realtime + 3
+  osPriorityRealtime4     = 48+4,       ///< Priority: realtime + 4
+  osPriorityRealtime5     = 48+5,       ///< Priority: realtime + 5
+  osPriorityRealtime6     = 48+6,       ///< Priority: realtime + 6
+  osPriorityRealtime7     = 48+7,       ///< Priority: realtime + 7
+  osPriorityISR           = 56,         ///< Reserved for ISR deferred thread.
+  osPriorityError         = -1,         ///< System cannot determine priority or illegal priority.
+  osPriorityReserved      = 0x7FFFFFFF  ///< Prevents enum down-size compiler optimization.
+} osPriority_t;
+ 
+/// Entry point of a thread.
+typedef void (*osThreadFunc_t) (void *argument);
+ 
+/// Timer callback function.
+typedef void (*osTimerFunc_t) (void *argument);
+ 
+/// Timer type.
+typedef enum {
+  osTimerOnce               = 0,          ///< One-shot timer.
+  osTimerPeriodic           = 1           ///< Repeating timer.
+} osTimerType_t;
+ 
+// Timeout value.
+#define osWaitForever         0xFFFFFFFFU ///< Wait forever timeout value.
+ 
+// Flags options (\ref osThreadFlagsWait and \ref osEventFlagsWait).
+#define osFlagsWaitAny        0x00000000U ///< Wait for any flag (default).
+#define osFlagsWaitAll        0x00000001U ///< Wait for all flags.
+#define osFlagsNoClear        0x00000002U ///< Do not clear flags which have been specified to wait for.
+ 
+// Flags errors (returned by osThreadFlagsXxxx and osEventFlagsXxxx).
+#define osFlagsError          0x80000000U ///< Error indicator.
+#define osFlagsErrorUnknown   0xFFFFFFFFU ///< osError (-1).
+#define osFlagsErrorTimeout   0xFFFFFFFEU ///< osErrorTimeout (-2).
+#define osFlagsErrorResource  0xFFFFFFFDU ///< osErrorResource (-3).
+#define osFlagsErrorParameter 0xFFFFFFFCU ///< osErrorParameter (-4).
+#define osFlagsErrorISR       0xFFFFFFFAU ///< osErrorISR (-6).
+ 
+// Thread attributes (attr_bits in \ref osThreadAttr_t).
+#define osThreadDetached      0x00000000U ///< Thread created in detached mode (default)
+#define osThreadJoinable      0x00000001U ///< Thread created in joinable mode
+ 
+// Mutex attributes (attr_bits in \ref osMutexAttr_t).
+#define osMutexRecursive      0x00000001U ///< Recursive mutex.
+#define osMutexPrioInherit    0x00000002U ///< Priority inherit protocol.
+#define osMutexRobust         0x00000008U ///< Robust mutex.
+ 
+/// Status code values returned by CMSIS-RTOS functions.
+typedef enum {
+  osOK                      =  0,         ///< Operation completed successfully.
+  osError                   = -1,         ///< Unspecified RTOS error: run-time error but no other error message fits.
+  osErrorTimeout            = -2,         ///< Operation not completed within the timeout period.
+  osErrorResource           = -3,         ///< Resource not available.
+  osErrorParameter          = -4,         ///< Parameter error.
+  osErrorNoMemory           = -5,         ///< System is out of memory: it was impossible to allocate or reserve memory for the operation.
+  osErrorISR                = -6,         ///< Not allowed in ISR context: the function cannot be called from interrupt service routines.
+  osStatusReserved          = 0x7FFFFFFF  ///< Prevents enum down-size compiler optimization.
+} osStatus_t;
+ 
+ 
+/// \details Thread ID identifies the thread.
+typedef void *osThreadId_t;
+ 
+/// \details Timer ID identifies the timer.
+typedef void *osTimerId_t;
+ 
+/// \details Event Flags ID identifies the event flags.
+typedef void *osEventFlagsId_t;
+ 
+/// \details Mutex ID identifies the mutex.
+typedef void *osMutexId_t;
+ 
+/// \details Semaphore ID identifies the semaphore.
+typedef void *osSemaphoreId_t;
+ 
+/// \details Memory Pool ID identifies the memory pool.
+typedef void *osMemoryPoolId_t;
+ 
+/// \details Message Queue ID identifies the message queue.
+typedef void *osMessageQueueId_t;
+ 
+ 
+#ifndef TZ_MODULEID_T
+#define TZ_MODULEID_T
+/// \details Data type that identifies secure software modules called by a process.
+typedef uint32_t TZ_ModuleId_t;
+#endif
+ 
+ 
+/// Attributes structure for thread.
+typedef struct {
+  const char                   *name;   ///< name of the thread
+  uint32_t                 attr_bits;   ///< attribute bits
+  void                      *cb_mem;    ///< memory for control block
+  uint32_t                   cb_size;   ///< size of provided memory for control block
+  void                   *stack_mem;    ///< memory for stack
+  uint32_t                stack_size;   ///< size of stack
+  osPriority_t              priority;   ///< initial thread priority (default: osPriorityNormal)
+  TZ_ModuleId_t            tz_module;   ///< TrustZone module identifier
+  uint32_t                  reserved;   ///< reserved (must be 0)
+} osThreadAttr_t;
+ 
+/// Attributes structure for timer.
+typedef struct {
+  const char                   *name;   ///< name of the timer
+  uint32_t                 attr_bits;   ///< attribute bits
+  void                      *cb_mem;    ///< memory for control block
+  uint32_t                   cb_size;   ///< size of provided memory for control block
+} osTimerAttr_t;
+ 
+/// Attributes structure for event flags.
+typedef struct {
+  const char                   *name;   ///< name of the event flags
+  uint32_t                 attr_bits;   ///< attribute bits
+  void                      *cb_mem;    ///< memory for control block
+  uint32_t                   cb_size;   ///< size of provided memory for control block
+} osEventFlagsAttr_t;
+ 
+/// Attributes structure for mutex.
+typedef struct {
+  const char                   *name;   ///< name of the mutex
+  uint32_t                 attr_bits;   ///< attribute bits
+  void                      *cb_mem;    ///< memory for control block
+  uint32_t                   cb_size;   ///< size of provided memory for control block
+} osMutexAttr_t;
+ 
+/// Attributes structure for semaphore.
+typedef struct {
+  const char                   *name;   ///< name of the semaphore
+  uint32_t                 attr_bits;   ///< attribute bits
+  void                      *cb_mem;    ///< memory for control block
+  uint32_t                   cb_size;   ///< size of provided memory for control block
+} osSemaphoreAttr_t;
+ 
+/// Attributes structure for memory pool.
+typedef struct {
+  const char                   *name;   ///< name of the memory pool
+  uint32_t                 attr_bits;   ///< attribute bits
+  void                      *cb_mem;    ///< memory for control block
+  uint32_t                   cb_size;   ///< size of provided memory for control block
+  void                      *mp_mem;    ///< memory for data storage
+  uint32_t                   mp_size;   ///< size of provided memory for data storage 
+} osMemoryPoolAttr_t;
+ 
+/// Attributes structure for message queue.
+typedef struct {
+  const char                   *name;   ///< name of the message queue
+  uint32_t                 attr_bits;   ///< attribute bits
+  void                      *cb_mem;    ///< memory for control block
+  uint32_t                   cb_size;   ///< size of provided memory for control block
+  void                      *mq_mem;    ///< memory for data storage
+  uint32_t                   mq_size;   ///< size of provided memory for data storage 
+} osMessageQueueAttr_t;
+ 
+ 
+//  ==== Kernel Management Functions ====
+ 
+/// Initialize the RTOS Kernel.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osKernelInitialize (void);
+ 
+///  Get RTOS Kernel Information.
+/// \param[out]    version       pointer to buffer for retrieving version information.
+/// \param[out]    id_buf        pointer to buffer for retrieving kernel identification string.
+/// \param[in]     id_size       size of buffer for kernel identification string.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osKernelGetInfo (osVersion_t *version, char *id_buf, uint32_t id_size);
+ 
+/// Get the current RTOS Kernel state.
+/// \return current RTOS Kernel state.
+osKernelState_t osKernelGetState (void);
+ 
+/// Start the RTOS Kernel scheduler.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osKernelStart (void);
+ 
+/// Lock the RTOS Kernel scheduler.
+/// \return previous lock state (1 - locked, 0 - not locked, error code if negative).
+int32_t osKernelLock (void);
+ 
+/// Unlock the RTOS Kernel scheduler.
+/// \return previous lock state (1 - locked, 0 - not locked, error code if negative).
+int32_t osKernelUnlock (void);
+ 
+/// Restore the RTOS Kernel scheduler lock state.
+/// \param[in]     lock          lock state obtained by \ref osKernelLock or \ref osKernelUnlock.
+/// \return new lock state (1 - locked, 0 - not locked, error code if negative).
+int32_t osKernelRestoreLock (int32_t lock);
+ 
+/// Suspend the RTOS Kernel scheduler.
+/// \return time in ticks, for how long the system can sleep or power-down.
+uint32_t osKernelSuspend (void);
+ 
+/// Resume the RTOS Kernel scheduler.
+/// \param[in]     sleep_ticks   time in ticks for how long the system was in sleep or power-down mode.
+void osKernelResume (uint32_t sleep_ticks);
+ 
+/// Get the RTOS kernel tick count.
+/// \return RTOS kernel current tick count.
+uint32_t osKernelGetTickCount (void);
+ 
+/// Get the RTOS kernel tick frequency.
+/// \return frequency of the kernel tick in hertz, i.e. kernel ticks per second.
+uint32_t osKernelGetTickFreq (void);
+ 
+/// Get the RTOS kernel system timer count.
+/// \return RTOS kernel current system timer count as 32-bit value.
+uint32_t osKernelGetSysTimerCount (void);
+ 
+/// Get the RTOS kernel system timer frequency.
+/// \return frequency of the system timer in hertz, i.e. timer ticks per second.
+uint32_t osKernelGetSysTimerFreq (void);
+ 
+ 
+//  ==== Thread Management Functions ====
+ 
+/// Create a thread and add it to Active Threads.
+/// \param[in]     func          thread function.
+/// \param[in]     argument      pointer that is passed to the thread function as start argument.
+/// \param[in]     attr          thread attributes; NULL: default values.
+/// \return thread ID for reference by other functions or NULL in case of error.
+osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr);
+ 
+/// Get name of a thread.
+/// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
+/// \return name as null-terminated string.
+const char *osThreadGetName (osThreadId_t thread_id);
+ 
+/// Return the thread ID of the current running thread.
+/// \return thread ID for reference by other functions or NULL in case of error.
+osThreadId_t osThreadGetId (void);
+ 
+/// Get current thread state of a thread.
+/// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
+/// \return current thread state of the specified thread.
+osThreadState_t osThreadGetState (osThreadId_t thread_id);
+ 
+/// Get stack size of a thread.
+/// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
+/// \return stack size in bytes.
+uint32_t osThreadGetStackSize (osThreadId_t thread_id);
+ 
+/// Get available stack space of a thread based on stack watermark recording during execution.
+/// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
+/// \return remaining stack space in bytes.
+uint32_t osThreadGetStackSpace (osThreadId_t thread_id);
+ 
+/// Change priority of a thread.
+/// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
+/// \param[in]     priority      new priority value for the thread function.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osThreadSetPriority (osThreadId_t thread_id, osPriority_t priority);
+ 
+/// Get current priority of a thread.
+/// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
+/// \return current priority value of the specified thread.
+osPriority_t osThreadGetPriority (osThreadId_t thread_id);
+ 
+/// Pass control to next thread that is in state \b READY.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osThreadYield (void);
+ 
+/// Suspend execution of a thread.
+/// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osThreadSuspend (osThreadId_t thread_id);
+ 
+/// Resume execution of a thread.
+/// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osThreadResume (osThreadId_t thread_id);
+ 
+/// Detach a thread (thread storage can be reclaimed when thread terminates).
+/// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osThreadDetach (osThreadId_t thread_id);
+ 
+/// Wait for specified thread to terminate.
+/// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osThreadJoin (osThreadId_t thread_id);
+ 
+/// Terminate execution of current running thread.
+__NO_RETURN void osThreadExit (void);
+ 
+/// Terminate execution of a thread.
+/// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osThreadTerminate (osThreadId_t thread_id);
+ 
+/// Get number of active threads.
+/// \return number of active threads.
+uint32_t osThreadGetCount (void);
+ 
+/// Enumerate active threads.
+/// \param[out]    thread_array  pointer to array for retrieving thread IDs.
+/// \param[in]     array_items   maximum number of items in array for retrieving thread IDs.
+/// \return number of enumerated threads.
+uint32_t osThreadEnumerate (osThreadId_t *thread_array, uint32_t array_items);
+ 
+ 
+//  ==== Thread Flags Functions ====
+ 
+/// Set the specified Thread Flags of a thread.
+/// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
+/// \param[in]     flags         specifies the flags of the thread that shall be set.
+/// \return thread flags after setting or error code if highest bit set.
+uint32_t osThreadFlagsSet (osThreadId_t thread_id, uint32_t flags);
+ 
+/// Clear the specified Thread Flags of current running thread.
+/// \param[in]     flags         specifies the flags of the thread that shall be cleared.
+/// \return thread flags before clearing or error code if highest bit set.
+uint32_t osThreadFlagsClear (uint32_t flags);
+ 
+/// Get the current Thread Flags of current running thread.
+/// \return current thread flags.
+uint32_t osThreadFlagsGet (void);
+ 
+/// Wait for one or more Thread Flags of the current running thread to become signaled.
+/// \param[in]     flags         specifies the flags to wait for.
+/// \param[in]     options       specifies flags options (osFlagsXxxx).
+/// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
+/// \return thread flags before clearing or error code if highest bit set.
+uint32_t osThreadFlagsWait (uint32_t flags, uint32_t options, uint32_t timeout);
+ 
+ 
+//  ==== Generic Wait Functions ====
+ 
+/// Wait for Timeout (Time Delay).
+/// \param[in]     ticks         \ref CMSIS_RTOS_TimeOutValue "time ticks" value
+/// \return status code that indicates the execution status of the function.
+osStatus_t osDelay (uint32_t ticks);
+ 
+/// Wait until specified time.
+/// \param[in]     ticks         absolute time in ticks
+/// \return status code that indicates the execution status of the function.
+osStatus_t osDelayUntil (uint32_t ticks);
+ 
+ 
+//  ==== Timer Management Functions ====
+ 
+/// Create and Initialize a timer.
+/// \param[in]     func          function pointer to callback function.
+/// \param[in]     type          \ref osTimerOnce for one-shot or \ref osTimerPeriodic for periodic behavior.
+/// \param[in]     argument      argument to the timer callback function.
+/// \param[in]     attr          timer attributes; NULL: default values.
+/// \return timer ID for reference by other functions or NULL in case of error.
+osTimerId_t osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr);
+ 
+/// Get name of a timer.
+/// \param[in]     timer_id      timer ID obtained by \ref osTimerNew.
+/// \return name as null-terminated string.
+const char *osTimerGetName (osTimerId_t timer_id);
+ 
+/// Start or restart a timer.
+/// \param[in]     timer_id      timer ID obtained by \ref osTimerNew.
+/// \param[in]     ticks         \ref CMSIS_RTOS_TimeOutValue "time ticks" value of the timer.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osTimerStart (osTimerId_t timer_id, uint32_t ticks);
+ 
+/// Stop a timer.
+/// \param[in]     timer_id      timer ID obtained by \ref osTimerNew.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osTimerStop (osTimerId_t timer_id);
+ 
+/// Check if a timer is running.
+/// \param[in]     timer_id      timer ID obtained by \ref osTimerNew.
+/// \return 0 not running, 1 running.
+uint32_t osTimerIsRunning (osTimerId_t timer_id);
+ 
+/// Delete a timer.
+/// \param[in]     timer_id      timer ID obtained by \ref osTimerNew.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osTimerDelete (osTimerId_t timer_id);
+ 
+ 
+//  ==== Event Flags Management Functions ====
+ 
+/// Create and Initialize an Event Flags object.
+/// \param[in]     attr          event flags attributes; NULL: default values.
+/// \return event flags ID for reference by other functions or NULL in case of error.
+osEventFlagsId_t osEventFlagsNew (const osEventFlagsAttr_t *attr);
+ 
+/// Get name of an Event Flags object.
+/// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
+/// \return name as null-terminated string.
+const char *osEventFlagsGetName (osEventFlagsId_t ef_id);
+ 
+/// Set the specified Event Flags.
+/// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
+/// \param[in]     flags         specifies the flags that shall be set.
+/// \return event flags after setting or error code if highest bit set.
+uint32_t osEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags);
+ 
+/// Clear the specified Event Flags.
+/// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
+/// \param[in]     flags         specifies the flags that shall be cleared.
+/// \return event flags before clearing or error code if highest bit set.
+uint32_t osEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags);
+ 
+/// Get the current Event Flags.
+/// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
+/// \return current event flags.
+uint32_t osEventFlagsGet (osEventFlagsId_t ef_id);
+ 
+/// Wait for one or more Event Flags to become signaled.
+/// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
+/// \param[in]     flags         specifies the flags to wait for.
+/// \param[in]     options       specifies flags options (osFlagsXxxx).
+/// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
+/// \return event flags before clearing or error code if highest bit set.
+uint32_t osEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout);
+ 
+/// Delete an Event Flags object.
+/// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osEventFlagsDelete (osEventFlagsId_t ef_id);
+ 
+ 
+//  ==== Mutex Management Functions ====
+ 
+/// Create and Initialize a Mutex object.
+/// \param[in]     attr          mutex attributes; NULL: default values.
+/// \return mutex ID for reference by other functions or NULL in case of error.
+osMutexId_t osMutexNew (const osMutexAttr_t *attr);
+ 
+/// Get name of a Mutex object.
+/// \param[in]     mutex_id      mutex ID obtained by \ref osMutexNew.
+/// \return name as null-terminated string.
+const char *osMutexGetName (osMutexId_t mutex_id);
+ 
+/// Acquire a Mutex or timeout if it is locked.
+/// \param[in]     mutex_id      mutex ID obtained by \ref osMutexNew.
+/// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout);
+ 
+/// Release a Mutex that was acquired by \ref osMutexAcquire.
+/// \param[in]     mutex_id      mutex ID obtained by \ref osMutexNew.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osMutexRelease (osMutexId_t mutex_id);
+ 
+/// Get Thread which owns a Mutex object.
+/// \param[in]     mutex_id      mutex ID obtained by \ref osMutexNew.
+/// \return thread ID of owner thread or NULL when mutex was not acquired.
+osThreadId_t osMutexGetOwner (osMutexId_t mutex_id);
+ 
+/// Delete a Mutex object.
+/// \param[in]     mutex_id      mutex ID obtained by \ref osMutexNew.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osMutexDelete (osMutexId_t mutex_id);
+ 
+ 
+//  ==== Semaphore Management Functions ====
+ 
+/// Create and Initialize a Semaphore object.
+/// \param[in]     max_count     maximum number of available tokens.
+/// \param[in]     initial_count initial number of available tokens.
+/// \param[in]     attr          semaphore attributes; NULL: default values.
+/// \return semaphore ID for reference by other functions or NULL in case of error.
+osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr);
+ 
+/// Get name of a Semaphore object.
+/// \param[in]     semaphore_id  semaphore ID obtained by \ref osSemaphoreNew.
+/// \return name as null-terminated string.
+const char *osSemaphoreGetName (osSemaphoreId_t semaphore_id);
+ 
+/// Acquire a Semaphore token or timeout if no tokens are available.
+/// \param[in]     semaphore_id  semaphore ID obtained by \ref osSemaphoreNew.
+/// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout);
+ 
+/// Release a Semaphore token up to the initial maximum count.
+/// \param[in]     semaphore_id  semaphore ID obtained by \ref osSemaphoreNew.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id);
+ 
+/// Get current Semaphore token count.
+/// \param[in]     semaphore_id  semaphore ID obtained by \ref osSemaphoreNew.
+/// \return number of tokens available.
+uint32_t osSemaphoreGetCount (osSemaphoreId_t semaphore_id);
+ 
+/// Delete a Semaphore object.
+/// \param[in]     semaphore_id  semaphore ID obtained by \ref osSemaphoreNew.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id);
+ 
+ 
+//  ==== Memory Pool Management Functions ====
+ 
+/// Create and Initialize a Memory Pool object.
+/// \param[in]     block_count   maximum number of memory blocks in memory pool.
+/// \param[in]     block_size    memory block size in bytes.
+/// \param[in]     attr          memory pool attributes; NULL: default values.
+/// \return memory pool ID for reference by other functions or NULL in case of error.
+osMemoryPoolId_t osMemoryPoolNew (uint32_t block_count, uint32_t block_size, const osMemoryPoolAttr_t *attr);
+ 
+/// Get name of a Memory Pool object.
+/// \param[in]     mp_id         memory pool ID obtained by \ref osMemoryPoolNew.
+/// \return name as null-terminated string.
+const char *osMemoryPoolGetName (osMemoryPoolId_t mp_id);
+ 
+/// Allocate a memory block from a Memory Pool.
+/// \param[in]     mp_id         memory pool ID obtained by \ref osMemoryPoolNew.
+/// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
+/// \return address of the allocated memory block or NULL in case of no memory is available.
+void *osMemoryPoolAlloc (osMemoryPoolId_t mp_id, uint32_t timeout);
+ 
+/// Return an allocated memory block back to a Memory Pool.
+/// \param[in]     mp_id         memory pool ID obtained by \ref osMemoryPoolNew.
+/// \param[in]     block         address of the allocated memory block to be returned to the memory pool.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osMemoryPoolFree (osMemoryPoolId_t mp_id, void *block);
+ 
+/// Get maximum number of memory blocks in a Memory Pool.
+/// \param[in]     mp_id         memory pool ID obtained by \ref osMemoryPoolNew.
+/// \return maximum number of memory blocks.
+uint32_t osMemoryPoolGetCapacity (osMemoryPoolId_t mp_id);
+ 
+/// Get memory block size in a Memory Pool.
+/// \param[in]     mp_id         memory pool ID obtained by \ref osMemoryPoolNew.
+/// \return memory block size in bytes.
+uint32_t osMemoryPoolGetBlockSize (osMemoryPoolId_t mp_id);
+ 
+/// Get number of memory blocks used in a Memory Pool.
+/// \param[in]     mp_id         memory pool ID obtained by \ref osMemoryPoolNew.
+/// \return number of memory blocks used.
+uint32_t osMemoryPoolGetCount (osMemoryPoolId_t mp_id);
+ 
+/// Get number of memory blocks available in a Memory Pool.
+/// \param[in]     mp_id         memory pool ID obtained by \ref osMemoryPoolNew.
+/// \return number of memory blocks available.
+uint32_t osMemoryPoolGetSpace (osMemoryPoolId_t mp_id);
+ 
+/// Delete a Memory Pool object.
+/// \param[in]     mp_id         memory pool ID obtained by \ref osMemoryPoolNew.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osMemoryPoolDelete (osMemoryPoolId_t mp_id);
+ 
+ 
+//  ==== Message Queue Management Functions ====
+ 
+/// Create and Initialize a Message Queue object.
+/// \param[in]     msg_count     maximum number of messages in queue.
+/// \param[in]     msg_size      maximum message size in bytes.
+/// \param[in]     attr          message queue attributes; NULL: default values.
+/// \return message queue ID for reference by other functions or NULL in case of error.
+osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr);
+ 
+/// Get name of a Message Queue object.
+/// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
+/// \return name as null-terminated string.
+const char *osMessageQueueGetName (osMessageQueueId_t mq_id);
+ 
+/// Put a Message into a Queue or timeout if Queue is full.
+/// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
+/// \param[in]     msg_ptr       pointer to buffer with message to put into a queue.
+/// \param[in]     msg_prio      message priority.
+/// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout);
+ 
+/// Get a Message from a Queue or timeout if Queue is empty.
+/// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
+/// \param[out]    msg_ptr       pointer to buffer for message to get from a queue.
+/// \param[out]    msg_prio      pointer to buffer for message priority or NULL.
+/// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout);
+ 
+/// Get maximum number of messages in a Message Queue.
+/// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
+/// \return maximum number of messages.
+uint32_t osMessageQueueGetCapacity (osMessageQueueId_t mq_id);
+ 
+/// Get maximum message size in a Message Queue.
+/// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
+/// \return maximum message size in bytes.
+uint32_t osMessageQueueGetMsgSize (osMessageQueueId_t mq_id);
+ 
+/// Get number of queued messages in a Message Queue.
+/// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
+/// \return number of queued messages.
+uint32_t osMessageQueueGetCount (osMessageQueueId_t mq_id);
+ 
+/// Get number of available slots for messages in a Message Queue.
+/// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
+/// \return number of available slots for messages.
+uint32_t osMessageQueueGetSpace (osMessageQueueId_t mq_id);
+ 
+/// Reset a Message Queue to initial empty state.
+/// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osMessageQueueReset (osMessageQueueId_t mq_id);
+ 
+/// Delete a Message Queue object.
+/// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
+/// \return status code that indicates the execution status of the function.
+osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id);
+ 
+ 
+#ifdef  __cplusplus
+}
+#endif
+ 
+#endif  // CMSIS_OS2_H_

+ 63 - 0
lib/FreeRTOS-glue/freertos_mpool.h

@@ -0,0 +1,63 @@
+/* --------------------------------------------------------------------------
+ * Copyright (c) 2013-2020 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *      Name:    freertos_mpool.h
+ *      Purpose: CMSIS RTOS2 wrapper for FreeRTOS
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifndef FREERTOS_MPOOL_H_
+#define FREERTOS_MPOOL_H_
+
+#include <stdint.h>
+#include "FreeRTOS.h"
+#include "semphr.h"
+
+/* Memory Pool implementation definitions */
+#define MPOOL_STATUS              0x5EED0000U
+
+/* Memory Block header */
+typedef struct {
+  void *next;                   /* Pointer to next block  */
+} MemPoolBlock_t;
+
+/* Memory Pool control block */
+typedef struct MemPoolDef_t {
+  MemPoolBlock_t    *head;      /* Pointer to head block   */
+  SemaphoreHandle_t  sem;       /* Pool semaphore handle   */
+  uint8_t           *mem_arr;   /* Pool memory array       */
+  uint32_t           mem_sz;    /* Pool memory array size  */
+  const char        *name;      /* Pointer to name string  */
+  uint32_t           bl_sz;     /* Size of a single block  */
+  uint32_t           bl_cnt;    /* Number of blocks        */
+  uint32_t           n;         /* Block allocation index  */
+  volatile uint32_t  status;    /* Object status flags     */
+#if (configSUPPORT_STATIC_ALLOCATION == 1)
+  StaticSemaphore_t  mem_sem;   /* Semaphore object memory */
+#endif
+} MemPool_t;
+
+/* No need to hide static object type, just align to coding style */
+#define StaticMemPool_t         MemPool_t
+
+/* Define memory pool control block size */
+#define MEMPOOL_CB_SIZE         (sizeof(StaticMemPool_t))
+
+/* Define size of the byte array required to create count of blocks of given size */
+#define MEMPOOL_ARR_SIZE(bl_count, bl_size) (((((bl_size) + (4 - 1)) / 4) * 4)*(bl_count))
+
+#endif /* FREERTOS_MPOOL_H_ */

+ 336 - 0
lib/FreeRTOS-glue/freertos_os2.h

@@ -0,0 +1,336 @@
+/* --------------------------------------------------------------------------
+ * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *      Name:    freertos_os2.h
+ *      Purpose: CMSIS RTOS2 wrapper for FreeRTOS
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifndef FREERTOS_OS2_H_
+#define FREERTOS_OS2_H_
+
+#include <string.h>
+#include <stdint.h>
+
+#include "FreeRTOS.h"                   // ARM.FreeRTOS::RTOS:Core
+
+#if defined(_RTE_)
+#include "RTE_Components.h"             // Component selection
+#include CMSIS_device_header
+
+/* Configuration and component setup check */
+#if defined(RTE_Compiler_EventRecorder)
+  #if !defined(EVR_FREERTOS_DISABLE)
+    #define USE_TRACE_EVENT_RECORDER
+    /*
+      FreeRTOS provides functions and hooks to support execution tracing. This
+      functionality is only enabled if configUSE_TRACE_FACILITY == 1.
+      Set #define configUSE_TRACE_FACILITY 1 in FreeRTOSConfig.h to enable trace events.
+    */
+    #if (configUSE_TRACE_FACILITY == 0)
+      #error "Definition configUSE_TRACE_FACILITY must equal 1 to enable FreeRTOS trace events."
+    #endif
+  #endif
+#endif
+
+#if defined(RTE_RTOS_FreeRTOS_HEAP_1)
+  #define USE_FreeRTOS_HEAP_1
+#endif
+
+#if defined(RTE_RTOS_FreeRTOS_HEAP_5)
+  #define USE_FreeRTOS_HEAP_5
+#endif
+#endif /* _RTE_ */
+
+/*
+  CMSIS-RTOS2 FreeRTOS image size optimization definitions.
+
+  Note: Definitions configUSE_OS2 can be used to optimize FreeRTOS image size when
+        certain functionality is not required when using CMSIS-RTOS2 API.
+        In general optimization decisions are left to the tool chain but in cases
+        when coding style prevents it to optimize the code following optional
+        definitions can be used.
+*/
+
+/*
+  Option to exclude CMSIS-RTOS2 functions osThreadSuspend and osThreadResume from
+  the application image.
+*/
+#ifndef configUSE_OS2_THREAD_SUSPEND_RESUME
+#define configUSE_OS2_THREAD_SUSPEND_RESUME   1
+#endif
+
+/*
+  Option to exclude CMSIS-RTOS2 function osThreadEnumerate from the application image.
+*/
+#ifndef configUSE_OS2_THREAD_ENUMERATE
+#define configUSE_OS2_THREAD_ENUMERATE        1
+#endif
+
+/*
+  Option to disable CMSIS-RTOS2 function osEventFlagsSet and osEventFlagsClear
+  operation from ISR.
+*/
+#ifndef configUSE_OS2_EVENTFLAGS_FROM_ISR
+#define configUSE_OS2_EVENTFLAGS_FROM_ISR     1
+#endif
+
+/*
+  Option to exclude CMSIS-RTOS2 Thread Flags API functions from the application image.
+*/
+#ifndef configUSE_OS2_THREAD_FLAGS
+#define configUSE_OS2_THREAD_FLAGS            configUSE_TASK_NOTIFICATIONS
+#endif
+
+/*
+  Option to exclude CMSIS-RTOS2 Timer API functions from the application image.
+*/
+#ifndef configUSE_OS2_TIMER
+#define configUSE_OS2_TIMER                   configUSE_TIMERS
+#endif
+
+/*
+  Option to exclude CMSIS-RTOS2 Mutex API functions from the application image.
+*/
+#ifndef configUSE_OS2_MUTEX
+#define configUSE_OS2_MUTEX                   configUSE_MUTEXES
+#endif
+
+
+/*
+  CMSIS-RTOS2 FreeRTOS configuration check (FreeRTOSConfig.h).
+
+  Note: CMSIS-RTOS API requires functions included by using following definitions.
+        In case if certain API function is not used compiler will optimize it away.
+*/
+#if (INCLUDE_xSemaphoreGetMutexHolder == 0)
+  /*
+    CMSIS-RTOS2 function osMutexGetOwner uses FreeRTOS function xSemaphoreGetMutexHolder. In case if
+    osMutexGetOwner is not used in the application image, compiler will optimize it away.
+    Set #define INCLUDE_xSemaphoreGetMutexHolder 1 to fix this error.
+  */
+  #error "Definition INCLUDE_xSemaphoreGetMutexHolder must equal 1 to implement Mutex Management API."
+#endif
+#if (INCLUDE_vTaskDelay == 0)
+  /*
+    CMSIS-RTOS2 function osDelay uses FreeRTOS function vTaskDelay. In case if
+    osDelay is not used in the application image, compiler will optimize it away.
+    Set #define INCLUDE_vTaskDelay 1 to fix this error.
+  */
+  #error "Definition INCLUDE_vTaskDelay must equal 1 to implement Generic Wait Functions API."
+#endif
+#if (INCLUDE_xTaskDelayUntil == 0)
+  /*
+    CMSIS-RTOS2 function osDelayUntil uses FreeRTOS function xTaskDelayUntil. In case if
+    osDelayUntil is not used in the application image, compiler will optimize it away.
+    Set #define INCLUDE_xTaskDelayUntil 1 to fix this error.
+  */
+  #error "Definition INCLUDE_xTaskDelayUntil must equal 1 to implement Generic Wait Functions API."
+#endif
+#if (INCLUDE_vTaskDelete == 0)
+  /*
+    CMSIS-RTOS2 function osThreadTerminate and osThreadExit uses FreeRTOS function
+    vTaskDelete. In case if they are not used in the application image, compiler
+    will optimize them away.
+    Set #define INCLUDE_vTaskDelete 1 to fix this error.
+  */
+  #error "Definition INCLUDE_vTaskDelete must equal 1 to implement Thread Management API."
+#endif
+#if (INCLUDE_xTaskGetCurrentTaskHandle == 0)
+  /*
+    CMSIS-RTOS2 API uses FreeRTOS function xTaskGetCurrentTaskHandle to implement
+    functions osThreadGetId, osThreadFlagsClear and osThreadFlagsGet. In case if these
+    functions are not used in the application image, compiler will optimize them away.
+    Set #define INCLUDE_xTaskGetCurrentTaskHandle 1 to fix this error.
+  */
+  #error "Definition INCLUDE_xTaskGetCurrentTaskHandle must equal 1 to implement Thread Management API."
+#endif
+#if (INCLUDE_xTaskGetSchedulerState == 0)
+  /*
+    CMSIS-RTOS2 API uses FreeRTOS function xTaskGetSchedulerState to implement Kernel
+    tick handling and therefore it is vital that xTaskGetSchedulerState is included into
+    the application image.
+    Set #define INCLUDE_xTaskGetSchedulerState 1 to fix this error.
+  */
+  #error "Definition INCLUDE_xTaskGetSchedulerState must equal 1 to implement Kernel Information and Control API."
+#endif
+#if (INCLUDE_uxTaskGetStackHighWaterMark == 0)
+  /*
+    CMSIS-RTOS2 function osThreadGetStackSpace uses FreeRTOS function uxTaskGetStackHighWaterMark.
+    In case if osThreadGetStackSpace is not used in the application image, compiler will
+    optimize it away.
+    Set #define INCLUDE_uxTaskGetStackHighWaterMark 1 to fix this error.
+  */
+  #error "Definition INCLUDE_uxTaskGetStackHighWaterMark must equal 1 to implement Thread Management API."
+#endif
+#if (INCLUDE_uxTaskPriorityGet == 0)
+  /*
+    CMSIS-RTOS2 function osThreadGetPriority uses FreeRTOS function uxTaskPriorityGet. In case if
+    osThreadGetPriority is not used in the application image, compiler will optimize it away.
+    Set #define INCLUDE_uxTaskPriorityGet 1 to fix this error.
+  */
+  #error "Definition INCLUDE_uxTaskPriorityGet must equal 1 to implement Thread Management API."
+#endif
+#if (INCLUDE_vTaskPrioritySet == 0)
+  /*
+    CMSIS-RTOS2 function osThreadSetPriority uses FreeRTOS function vTaskPrioritySet. In case if
+    osThreadSetPriority is not used in the application image, compiler will optimize it away.
+    Set #define INCLUDE_vTaskPrioritySet 1 to fix this error.
+  */
+  #error "Definition INCLUDE_vTaskPrioritySet must equal 1 to implement Thread Management API."
+#endif
+#if (INCLUDE_eTaskGetState == 0)
+  /*
+    CMSIS-RTOS2 API uses FreeRTOS function vTaskDelayUntil to implement functions osThreadGetState
+    and osThreadTerminate. In case if these functions are not used in the application image,
+    compiler will optimize them away.
+    Set #define INCLUDE_eTaskGetState 1 to fix this error.
+  */
+  #error "Definition INCLUDE_eTaskGetState must equal 1 to implement Thread Management API."
+#endif
+#if (INCLUDE_vTaskSuspend == 0)
+  /*
+    CMSIS-RTOS2 API uses FreeRTOS functions vTaskSuspend and vTaskResume to implement
+    functions osThreadSuspend and osThreadResume. In case if these functions are not
+    used in the application image, compiler will optimize them away.
+    Set #define INCLUDE_vTaskSuspend 1 to fix this error.
+
+    Alternatively, if the application does not use osThreadSuspend and
+    osThreadResume they can be excluded from the image code by setting:
+    #define configUSE_OS2_THREAD_SUSPEND_RESUME 0 (in FreeRTOSConfig.h)
+  */
+  #if (configUSE_OS2_THREAD_SUSPEND_RESUME == 1)
+    #error "Definition INCLUDE_vTaskSuspend must equal 1 to implement Kernel Information and Control API."
+  #endif
+#endif
+#if (INCLUDE_xTimerPendFunctionCall == 0)
+  /*
+    CMSIS-RTOS2 function osEventFlagsSet and osEventFlagsClear, when called from
+    the ISR, call FreeRTOS functions xEventGroupSetBitsFromISR and
+    xEventGroupClearBitsFromISR which are only enabled if timers are operational and
+    xTimerPendFunctionCall in enabled.
+    Set #define INCLUDE_xTimerPendFunctionCall 1 and #define configUSE_TIMERS 1
+    to fix this error.
+
+    Alternatively, if the application does not use osEventFlagsSet and osEventFlagsClear
+    from the ISR their operation from ISR can be restricted by setting:
+    #define configUSE_OS2_EVENTFLAGS_FROM_ISR 0 (in FreeRTOSConfig.h)
+  */
+  #if (configUSE_OS2_EVENTFLAGS_FROM_ISR == 1)
+    #error "Definition INCLUDE_xTimerPendFunctionCall must equal 1 to implement Event Flags API."
+  #endif
+#endif
+
+#if (configUSE_TIMERS == 0)
+  /*
+    CMSIS-RTOS2 Timer Management API functions use FreeRTOS timer functions to implement
+    timer management. In case if these functions are not used in the application image,
+    compiler will optimize them away.
+    Set #define configUSE_TIMERS 1 to fix this error.
+
+    Alternatively, if the application does not use timer functions they can be
+    excluded from the image code by setting:
+    #define configUSE_OS2_TIMER 0 (in FreeRTOSConfig.h)
+  */
+  #if (configUSE_OS2_TIMER == 1)
+    #error "Definition configUSE_TIMERS must equal 1 to implement Timer Management API."
+  #endif
+#endif
+
+#if (configUSE_MUTEXES == 0)
+  /*
+    CMSIS-RTOS2 Mutex Management API functions use FreeRTOS mutex functions to implement
+    mutex management. In case if these functions are not used in the application image,
+    compiler will optimize them away.
+    Set #define configUSE_MUTEXES 1 to fix this error.
+
+    Alternatively, if the application does not use mutex functions they can be
+    excluded from the image code by setting:
+    #define configUSE_OS2_MUTEX 0 (in FreeRTOSConfig.h)
+  */
+  #if (configUSE_OS2_MUTEX == 1)
+    #error "Definition configUSE_MUTEXES must equal 1 to implement Mutex Management API."
+  #endif
+#endif
+
+#if (configUSE_COUNTING_SEMAPHORES == 0)
+  /*
+    CMSIS-RTOS2 Memory Pool functions use FreeRTOS function xSemaphoreCreateCounting
+    to implement memory pools. In case if these functions are not used in the application image,
+    compiler will optimize them away.
+    Set #define configUSE_COUNTING_SEMAPHORES 1 to fix this error.
+  */
+  #error "Definition configUSE_COUNTING_SEMAPHORES must equal 1 to implement Memory Pool API."
+#endif
+#if (configUSE_TASK_NOTIFICATIONS == 0)
+  /*
+    CMSIS-RTOS2 Thread Flags API functions use FreeRTOS Task Notification functions to implement
+    thread flag management. In case if these functions are not used in the application image,
+    compiler will optimize them away.
+    Set #define configUSE_TASK_NOTIFICATIONS 1 to fix this error.
+
+    Alternatively, if the application does not use thread flags functions they can be
+    excluded from the image code by setting:
+    #define configUSE_OS2_THREAD_FLAGS 0 (in FreeRTOSConfig.h)
+  */
+  #if (configUSE_OS2_THREAD_FLAGS == 1)
+    #error "Definition configUSE_TASK_NOTIFICATIONS must equal 1 to implement Thread Flags API."
+  #endif
+#endif
+
+#if (configUSE_TRACE_FACILITY == 0)
+  /*
+    CMSIS-RTOS2 function osThreadEnumerate requires FreeRTOS function uxTaskGetSystemState
+    which is only enabled if configUSE_TRACE_FACILITY == 1.
+    Set #define configUSE_TRACE_FACILITY 1 to fix this error.
+
+    Alternatively, if the application does not use osThreadEnumerate it can be
+    excluded from the image code by setting:
+    #define configUSE_OS2_THREAD_ENUMERATE 0 (in FreeRTOSConfig.h)
+  */
+  #if (configUSE_OS2_THREAD_ENUMERATE == 1)
+    #error "Definition configUSE_TRACE_FACILITY must equal 1 to implement osThreadEnumerate."
+  #endif
+#endif
+
+#if (configUSE_16_BIT_TICKS == 1)
+  /*
+    CMSIS-RTOS2 wrapper for FreeRTOS relies on 32-bit tick timer which is also optimal on
+    a 32-bit CPU architectures.
+    Set #define configUSE_16_BIT_TICKS 0 to fix this error.
+  */
+  #error "Definition configUSE_16_BIT_TICKS must be zero to implement CMSIS-RTOS2 API."
+#endif
+
+#if (configMAX_PRIORITIES != 56)
+  /*
+    CMSIS-RTOS2 defines 56 different priorities (see osPriority_t) and portable CMSIS-RTOS2
+    implementation should implement the same number of priorities.
+    Set #define configMAX_PRIORITIES 56 to fix this error.
+  */
+  #error "Definition configMAX_PRIORITIES must equal 56 to implement Thread Management API."
+#endif
+#if (configUSE_PORT_OPTIMISED_TASK_SELECTION != 0)
+  /*
+    CMSIS-RTOS2 requires handling of 56 different priorities (see osPriority_t) while FreeRTOS port
+    optimised selection for Cortex core only handles 32 different priorities.
+    Set #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 to fix this error.
+  */
+  #error "Definition configUSE_PORT_OPTIMISED_TASK_SELECTION must be zero to implement Thread Management API."
+#endif
+
+#endif /* FREERTOS_OS2_H_ */

+ 80 - 0
lib/FreeRTOS-glue/os_tick.h

@@ -0,0 +1,80 @@
+/**************************************************************************//**
+ * @file     os_tick.h
+ * @brief    CMSIS OS Tick header file
+ * @version  V1.0.2
+ * @date     19. March 2021
+ ******************************************************************************/
+/*
+ * Copyright (c) 2017-2021 ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OS_TICK_H
+#define OS_TICK_H
+
+#include <stdint.h>
+
+#ifdef  __cplusplus
+extern "C"
+{
+#endif
+
+/// IRQ Handler.
+#ifndef IRQHANDLER_T
+#define IRQHANDLER_T
+typedef void (*IRQHandler_t) (void);
+#endif
+
+/// Setup OS Tick timer to generate periodic RTOS Kernel Ticks
+/// \param[in]     freq         tick frequency in Hz
+/// \param[in]     handler      tick IRQ handler
+/// \return 0 on success, -1 on error.
+int32_t  OS_Tick_Setup (uint32_t freq, IRQHandler_t handler);
+
+/// Enable OS Tick timer interrupt
+void     OS_Tick_Enable (void);
+
+/// Disable OS Tick timer interrupt
+void     OS_Tick_Disable (void);
+
+/// Acknowledge execution of OS Tick timer interrupt
+void     OS_Tick_AcknowledgeIRQ (void);
+
+/// Get OS Tick timer IRQ number
+/// \return OS Tick IRQ number
+int32_t  OS_Tick_GetIRQn (void);
+
+/// Get OS Tick timer clock frequency
+/// \return OS Tick timer clock frequency in Hz
+uint32_t OS_Tick_GetClock (void);
+
+/// Get OS Tick timer interval reload value
+/// \return OS Tick timer interval reload value
+uint32_t OS_Tick_GetInterval (void);
+
+/// Get OS Tick timer counter value
+/// \return OS Tick timer counter value
+uint32_t OS_Tick_GetCount (void);
+
+/// Get OS Tick timer overflow status
+/// \return OS Tick overflow status (1 - overflow, 0 - no overflow).
+uint32_t OS_Tick_GetOverflow (void);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif  /* OS_TICK_H */

+ 1 - 1
lib/ST25RFAL002/platform.c

@@ -39,7 +39,7 @@ void platformSetIrqCallback(PlatformIrqCallback callback) {
     platform_irq_callback = callback;
     platform_irq_thread_attr.name = "RfalIrqWorker";
     platform_irq_thread_attr.stack_size = 1024;
-    platform_irq_thread_attr.priority = osPriorityISR;
+    platform_irq_thread_attr.priority = osPriorityRealtime;
     platform_irq_thread_id = osThreadNew(platformIrqWorker, NULL, &platform_irq_thread_attr);
     hal_gpio_add_int_callback(&pin, nfc_isr, NULL);
     // Disable interrupt callback as the pin is shared between 2 apps

+ 1 - 1
lib/STM32CubeWB

@@ -1 +1 @@
-Subproject commit 9c78e7f25506db18c35c6be51ab5aa14c7e0a622
+Subproject commit 528461f8276f06783d46461bfb31d77aa8bac419

+ 2 - 2
lib/lib.mk

@@ -88,7 +88,7 @@ C_SOURCES		+= $(wildcard $(LIB_DIR)/drivers/*.c)
 CFLAGS			+= -I$(LIB_DIR)/file_reader
 CPP_SOURCES		+= $(wildcard $(LIB_DIR)/file_reader/*.cpp)
 
-#irda lib
+# IR lib
 CFLAGS			+= -I$(LIB_DIR)/irda/encoder_decoder
 CFLAGS			+= -I$(LIB_DIR)/irda/worker
 C_SOURCES		+= $(wildcard $(LIB_DIR)/irda/encoder_decoder/*.c)
@@ -123,4 +123,4 @@ C_SOURCES		+= $(wildcard $(LIB_DIR)/heatshrink/*.c)
 
 # Toolbox
 CFLAGS			+= -I$(LIB_DIR)/flipper_file
-C_SOURCES		+= $(wildcard $(LIB_DIR)/flipper_file/*.c)
+C_SOURCES		+= $(wildcard $(LIB_DIR)/flipper_file/*.c)

+ 2 - 1
make/rules.mk

@@ -108,7 +108,8 @@ blackmagic:
 		-ex 'monitor swdp_scan' \
 		-ex 'monitor debug_bmp enable' \
 		-ex 'attach 1' \
-		-ex "set confirm off" \
+		-ex 'set confirm off' \
+		-ex 'set mem inaccessible-by-default off' \
 		-ex "source ../debug/FreeRTOS/FreeRTOS.py" \
 		-ex "source ../debug/PyCortexMDebug/PyCortexMDebug.py" \
 		-ex "svd_load $(SVD_FILE)" \

+ 5 - 5
scripts/flipper/copro.py

@@ -16,10 +16,10 @@ MANIFEST_TEMPLATE = {
             "version": {
                 "type": 1,
                 "major": 1,
-                "minor": 12,
-                "sub": 1,
+                "minor": 13,
+                "sub": 0,
                 "branch": 0,
-                "release": 1,
+                "release": 5,
             },
             "files": [],
         },
@@ -51,7 +51,7 @@ class Copro:
         if not cube_version or not cube_version.startswith("FW.WB"):
             raise Exception(f"Incorrect Cube package or version info")
         cube_version = cube_version.replace("FW.WB.", "", 1)
-        if cube_version != "1.12.1":
+        if cube_version != "1.13.1":
             raise Exception(f"Unknonwn cube version")
         self.version = cube_version
 
@@ -89,7 +89,7 @@ class Copro:
         self.addFile(
             manifest["copro"]["radio"]["files"],
             "stm32wb5x_BLE_Stack_full_fw.bin",
-            address="0x080CA000",
+            address="0x080C7000",
         )
         # Save manifest to
         json.dump(manifest, open(manifest_file, "w"))

+ 2 - 2
scripts/ob.data

@@ -14,7 +14,7 @@ IWDGSTOP:0x1:rw
 IWDGSW:0x1:rw
 IPCCDBA:0x0:rw
 ESE:0x1:r
-SFSA:0xCA:r
+SFSA:0xC7:r
 FSD:0x0:r
 DDS:0x1:r
 C2OPT:0x1:r
@@ -22,7 +22,7 @@ NBRSD:0x0:r
 SNBRSA:0xF:r
 BRSD:0x0:r
 SBRSA:0xA:r
-SBRV:0x32800:r
+SBRV:0x31C00:r
 PCROP1A_STRT:0x1FF:r
 PCROP1A_END:0x0:r
 PCROP_RDP:0x1:rw