Pārlūkot izejas kodu

[FL-2591] Furi: remove CMSIS thread api, migrate to FuriThread, remove unused CMSIS APIs (#1333)

* Furi: remove CMSIS thread api, migrate to FuriThread, remove unused CMSIS APIs
* Furi: magic thread catcher validating thread completion; backtrace improver
* Furi: allow furi_thread_get_current_id outside of thread context
* Furi: use IRQ instead of ISR for core primitives
あく 3 gadi atpakaļ
vecāks
revīzija
839e52ac32
61 mainītis faili ar 1546 papildinājumiem un 2121 dzēšanām
  1. 9 9
      applications/bad_usb/bad_usb_script.c
  2. 6 6
      applications/cli/cli_commands.c
  3. 10 9
      applications/cli/cli_vcp.c
  4. 4 3
      applications/debug_tools/uart_echo.c
  5. 14 12
      applications/gpio/usb_uart_bridge.c
  6. 6 5
      applications/gui/gui.c
  7. 1 1
      applications/gui/gui_i.h
  8. 9 9
      applications/gui/modules/file_browser_worker.c
  9. 3 3
      applications/input/input.c
  10. 1 1
      applications/input/input_i.h
  11. 6 9
      applications/loader/loader.c
  12. 1 1
      applications/loader/loader_i.h
  13. 4 4
      applications/rpc/rpc.c
  14. 5 7
      applications/rpc/rpc_gui.c
  15. 3 1
      applications/subghz/helpers/subghz_chat.c
  16. 6 6
      applications/u2f/u2f_hid.c
  17. 0 88
      applications/unit_tests/furi_valuemutex_test.c
  18. 0 5
      applications/unit_tests/minunit_test.c
  19. 2 2
      applications/unit_tests/storage/storage_test.c
  20. 2 2
      applications/unit_tests/subghz/subghz_test.c
  21. 2 2
      applications/updater/util/update_task.c
  22. 1 1
      applications/updater/util/update_task.h
  23. 5 2
      core/furi.h
  24. 45 0
      core/furi/base.h
  25. 4 1
      core/furi/check.c
  26. 1 0
      core/furi/check.h
  27. 222 0
      core/furi/event_flags.c
  28. 63 0
      core/furi/event_flags.h
  29. 1 0
      core/furi/log.c
  30. 7 7
      core/furi/memmgr_heap.c
  31. 4 4
      core/furi/memmgr_heap.h
  32. 217 0
      core/furi/mutex.c
  33. 56 0
      core/furi/mutex.h
  34. 1 1
      core/furi/pubsub.c
  35. 2 1
      core/furi/record.c
  36. 190 0
      core/furi/semaphore.c
  37. 57 0
      core/furi/semaphore.h
  38. 7 7
      core/furi/stdglue.c
  39. 260 33
      core/furi/thread.c
  40. 56 21
      core/furi/thread.h
  41. 1 0
      core/furi/valuemutex.h
  42. 5 2
      firmware/targets/f7/Inc/FreeRTOSConfig.h
  43. 10 8
      firmware/targets/f7/Src/main.c
  44. 6 5
      firmware/targets/f7/ble_glue/ble_app.c
  45. 5 5
      firmware/targets/f7/ble_glue/ble_glue.c
  46. 1 1
      firmware/targets/f7/furi_hal/furi_hal_bt.c
  47. 1 1
      firmware/targets/f7/furi_hal/furi_hal_crc.c
  48. 6 6
      firmware/targets/f7/furi_hal/furi_hal_flash.c
  49. 3 3
      firmware/targets/f7/furi_hal/furi_hal_nfc.c
  50. 2 2
      firmware/targets/f7/furi_hal/furi_hal_resources.c
  51. 1 1
      firmware/targets/f7/furi_hal/furi_hal_resources.h
  52. 11 7
      firmware/targets/f7/furi_hal/furi_hal_rfid.c
  53. 8 8
      firmware/targets/f7/furi_hal/furi_hal_usb.c
  54. 80 1092
      lib/FreeRTOS-glue/cmsis_os2.c
  55. 59 513
      lib/FreeRTOS-glue/cmsis_os2.h
  56. 0 63
      lib/FreeRTOS-glue/freertos_mpool.h
  57. 7 24
      lib/FreeRTOS-glue/freertos_os2.h
  58. 0 80
      lib/FreeRTOS-glue/os_tick.h
  59. 30 21
      lib/ST25RFAL002/platform.c
  60. 14 14
      lib/infrared/worker/infrared_worker.c
  61. 3 2
      lib/subghz/subghz_file_encoder_worker.c

+ 9 - 9
applications/bad_usb/bad_usb_script.c

@@ -440,9 +440,9 @@ static void bad_usb_hid_state_callback(bool state, void* context) {
     BadUsbScript* bad_usb = context;
 
     if(state == true)
-        osThreadFlagsSet(furi_thread_get_thread_id(bad_usb->thread), WorkerEvtConnect);
+        furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtConnect);
     else
-        osThreadFlagsSet(furi_thread_get_thread_id(bad_usb->thread), WorkerEvtDisconnect);
+        furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtDisconnect);
 }
 
 static int32_t bad_usb_worker(void* context) {
@@ -483,8 +483,8 @@ static int32_t bad_usb_worker(void* context) {
             bad_usb->st.state = worker_state;
 
         } else if(worker_state == BadUsbStateNotConnected) { // State: USB not connected
-            uint32_t flags =
-                osThreadFlagsWait(WorkerEvtEnd | WorkerEvtConnect, osFlagsWaitAny, osWaitForever);
+            uint32_t flags = furi_thread_flags_wait(
+                WorkerEvtEnd | WorkerEvtConnect, osFlagsWaitAny, osWaitForever);
             furi_check((flags & osFlagsError) == 0);
             if(flags & WorkerEvtEnd) {
                 break;
@@ -494,7 +494,7 @@ static int32_t bad_usb_worker(void* context) {
             bad_usb->st.state = worker_state;
 
         } else if(worker_state == BadUsbStateIdle) { // State: ready to start
-            uint32_t flags = osThreadFlagsWait(
+            uint32_t flags = furi_thread_flags_wait(
                 WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect,
                 osFlagsWaitAny,
                 osWaitForever);
@@ -518,7 +518,7 @@ static int32_t bad_usb_worker(void* context) {
 
         } else if(worker_state == BadUsbStateRunning) { // State: running
             uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val);
-            uint32_t flags = osThreadFlagsWait(
+            uint32_t flags = furi_thread_flags_wait(
                 WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, osFlagsWaitAny, delay_cur);
             delay_val -= delay_cur;
             if(!(flags & osFlagsError)) {
@@ -561,7 +561,7 @@ static int32_t bad_usb_worker(void* context) {
         } else if(
             (worker_state == BadUsbStateFileError) ||
             (worker_state == BadUsbStateScriptError)) { // State: error
-            uint32_t flags = osThreadFlagsWait(
+            uint32_t flags = furi_thread_flags_wait(
                 WorkerEvtEnd, osFlagsWaitAny, osWaitForever); // Waiting for exit command
             furi_check((flags & osFlagsError) == 0);
             if(flags & WorkerEvtEnd) {
@@ -605,7 +605,7 @@ BadUsbScript* bad_usb_script_open(string_t file_path) {
 
 void bad_usb_script_close(BadUsbScript* bad_usb) {
     furi_assert(bad_usb);
-    osThreadFlagsSet(furi_thread_get_thread_id(bad_usb->thread), WorkerEvtEnd);
+    furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtEnd);
     furi_thread_join(bad_usb->thread);
     furi_thread_free(bad_usb->thread);
     string_clear(bad_usb->file_path);
@@ -614,7 +614,7 @@ void bad_usb_script_close(BadUsbScript* bad_usb) {
 
 void bad_usb_script_toggle(BadUsbScript* bad_usb) {
     furi_assert(bad_usb);
-    osThreadFlagsSet(furi_thread_get_thread_id(bad_usb->thread), WorkerEvtToggle);
+    furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtToggle);
 }
 
 BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb) {

+ 6 - 6
applications/cli/cli_commands.c

@@ -255,19 +255,19 @@ void cli_command_ps(Cli* cli, string_t args, void* context) {
     UNUSED(context);
 
     const uint8_t threads_num_max = 32;
-    osThreadId_t threads_id[threads_num_max];
-    uint8_t thread_num = osThreadEnumerate(threads_id, threads_num_max);
+    FuriThreadId threads_ids[threads_num_max];
+    uint8_t thread_num = furi_thread_enumerate(threads_ids, threads_num_max);
     printf(
         "%-20s %-14s %-8s %-8s %s\r\n", "Name", "Stack start", "Heap", "Stack", "Stack min free");
     for(uint8_t i = 0; i < thread_num; i++) {
-        TaskControlBlock* tcb = (TaskControlBlock*)threads_id[i];
+        TaskControlBlock* tcb = (TaskControlBlock*)threads_ids[i];
         printf(
             "%-20s 0x%-12lx %-8d %-8ld %-8ld\r\n",
-            osThreadGetName(threads_id[i]),
+            furi_thread_get_name(threads_ids[i]),
             (uint32_t)tcb->pxStack,
-            memmgr_heap_get_thread_memory(threads_id[i]),
+            memmgr_heap_get_thread_memory(threads_ids[i]),
             (uint32_t)(tcb->pxEndOfStack - tcb->pxStack + 1) * sizeof(StackType_t),
-            osThreadGetStackSpace(threads_id[i]));
+            furi_thread_get_stack_space(threads_ids[i]));
     }
     printf("\r\nTotal: %d", thread_num);
 }

+ 10 - 9
applications/cli/cli_vcp.c

@@ -79,7 +79,7 @@ static void cli_vcp_init() {
 }
 
 static void cli_vcp_deinit() {
-    osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtStop);
+    furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtStop);
     furi_thread_join(vcp->thread);
     furi_thread_free(vcp->thread);
     vcp->thread = NULL;
@@ -102,7 +102,8 @@ static int32_t vcp_worker(void* context) {
     vcp->running = true;
 
     while(1) {
-        uint32_t flags = osThreadFlagsWait(VCP_THREAD_FLAG_ALL, osFlagsWaitAny, osWaitForever);
+        uint32_t flags =
+            furi_thread_flags_wait(VCP_THREAD_FLAG_ALL, osFlagsWaitAny, osWaitForever);
         furi_assert((flags & osFlagsError) == 0);
 
         // VCP session opened
@@ -232,7 +233,7 @@ static size_t cli_vcp_rx(uint8_t* buffer, size_t size, uint32_t timeout) {
         FURI_LOG_D(TAG, "rx %u ", batch_size);
 #endif
         if(len == 0) break;
-        osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtStreamRx);
+        furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtStreamRx);
         size -= len;
         buffer += len;
         rx_cnt += len;
@@ -261,7 +262,7 @@ static void cli_vcp_tx(const uint8_t* buffer, size_t size) {
         if(batch_size > USB_CDC_PKT_LEN) batch_size = USB_CDC_PKT_LEN;
 
         xStreamBufferSend(vcp->tx_stream, buffer, batch_size, osWaitForever);
-        osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtStreamTx);
+        furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtStreamTx);
 #ifdef CLI_VCP_DEBUG
         FURI_LOG_D(TAG, "tx %u", batch_size);
 #endif
@@ -283,7 +284,7 @@ static void cli_vcp_tx_stdout(void* _cookie, const char* data, size_t size) {
 static void vcp_state_callback(void* context, uint8_t state) {
     UNUSED(context);
     if(state == 0) {
-        osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtDisconnect);
+        furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtDisconnect);
     }
 }
 
@@ -293,21 +294,21 @@ static void vcp_on_cdc_control_line(void* context, uint8_t state) {
     bool dtr = state & (1 << 0);
 
     if(dtr == true) {
-        osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtConnect);
+        furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtConnect);
     } else {
-        osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtDisconnect);
+        furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtDisconnect);
     }
 }
 
 static void vcp_on_cdc_rx(void* context) {
     UNUSED(context);
-    uint32_t ret = osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtRx);
+    uint32_t ret = furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtRx);
     furi_check((ret & osFlagsError) == 0);
 }
 
 static void vcp_on_cdc_tx_complete(void* context) {
     UNUSED(context);
-    osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtTx);
+    furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtTx);
 }
 
 static bool cli_vcp_is_connected(void) {

+ 4 - 3
applications/debug_tools/uart_echo.c

@@ -97,7 +97,7 @@ static void uart_echo_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) {
 
     if(ev == UartIrqEventRXNE) {
         xStreamBufferSendFromISR(app->rx_stream, &data, 1, &xHigherPriorityTaskWoken);
-        osThreadFlagsSet(furi_thread_get_thread_id(app->worker_thread), WorkerEventRx);
+        furi_thread_flags_set(furi_thread_get_id(app->worker_thread), WorkerEventRx);
         portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
     }
 }
@@ -149,7 +149,8 @@ static int32_t uart_echo_worker(void* context) {
     UartEchoApp* app = context;
 
     while(1) {
-        uint32_t events = osThreadFlagsWait(WORKER_EVENTS_MASK, osFlagsWaitAny, osWaitForever);
+        uint32_t events =
+            furi_thread_flags_wait(WORKER_EVENTS_MASK, osFlagsWaitAny, osWaitForever);
         furi_check((events & osFlagsError) == 0);
 
         if(events & WorkerEventStop) break;
@@ -234,7 +235,7 @@ static UartEchoApp* uart_echo_app_alloc() {
 static void uart_echo_app_free(UartEchoApp* app) {
     furi_assert(app);
 
-    osThreadFlagsSet(furi_thread_get_thread_id(app->worker_thread), WorkerEventStop);
+    furi_thread_flags_set(furi_thread_get_id(app->worker_thread), WorkerEventStop);
     furi_thread_join(app->worker_thread);
     furi_thread_free(app->worker_thread);
 

+ 14 - 12
applications/gpio/usb_uart_bridge.c

@@ -78,7 +78,7 @@ static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) {
 
     if(ev == UartIrqEventRXNE) {
         xStreamBufferSendFromISR(usb_uart->rx_stream, &data, 1, &xHigherPriorityTaskWoken);
-        osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->thread), WorkerEvtRxDone);
+        furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtRxDone);
         portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
     }
 }
@@ -181,12 +181,13 @@ static int32_t usb_uart_worker(void* context) {
         usb_uart_update_ctrl_lines(usb_uart);
     }
 
-    osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->tx_thread), WorkerEvtCdcRx);
+    furi_thread_flags_set(furi_thread_get_id(usb_uart->tx_thread), WorkerEvtCdcRx);
 
     furi_thread_start(usb_uart->tx_thread);
 
     while(1) {
-        uint32_t events = osThreadFlagsWait(WORKER_ALL_RX_EVENTS, osFlagsWaitAny, osWaitForever);
+        uint32_t events =
+            furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, osFlagsWaitAny, osWaitForever);
         furi_check((events & osFlagsError) == 0);
         if(events & WorkerEvtStop) break;
         if(events & WorkerEvtRxDone) {
@@ -205,7 +206,7 @@ static int32_t usb_uart_worker(void* context) {
         }
         if(events & WorkerEvtCfgChange) {
             if(usb_uart->cfg.vcp_ch != usb_uart->cfg_new.vcp_ch) {
-                osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->tx_thread), WorkerEvtTxStop);
+                furi_thread_flags_set(furi_thread_get_id(usb_uart->tx_thread), WorkerEvtTxStop);
                 furi_thread_join(usb_uart->tx_thread);
 
                 usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch);
@@ -217,7 +218,7 @@ static int32_t usb_uart_worker(void* context) {
                 events |= WorkerEvtLineCfgSet;
             }
             if(usb_uart->cfg.uart_ch != usb_uart->cfg_new.uart_ch) {
-                osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->tx_thread), WorkerEvtTxStop);
+                furi_thread_flags_set(furi_thread_get_id(usb_uart->tx_thread), WorkerEvtTxStop);
                 furi_thread_join(usb_uart->tx_thread);
 
                 usb_uart_serial_deinit(usb_uart, usb_uart->cfg.uart_ch);
@@ -266,7 +267,7 @@ static int32_t usb_uart_worker(void* context) {
         furi_hal_gpio_init_simple(flow_pins[usb_uart->cfg.flow_pins - 1][1], GpioModeAnalog);
     }
 
-    osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->tx_thread), WorkerEvtTxStop);
+    furi_thread_flags_set(furi_thread_get_id(usb_uart->tx_thread), WorkerEvtTxStop);
     furi_thread_join(usb_uart->tx_thread);
     furi_thread_free(usb_uart->tx_thread);
 
@@ -288,7 +289,8 @@ static int32_t usb_uart_tx_thread(void* context) {
 
     uint8_t data[USB_CDC_PKT_LEN];
     while(1) {
-        uint32_t events = osThreadFlagsWait(WORKER_ALL_TX_EVENTS, osFlagsWaitAny, osWaitForever);
+        uint32_t events =
+            furi_thread_flags_wait(WORKER_ALL_TX_EVENTS, osFlagsWaitAny, osWaitForever);
         furi_check((events & osFlagsError) == 0);
         if(events & WorkerEvtTxStop) break;
         if(events & WorkerEvtCdcRx) {
@@ -314,7 +316,7 @@ static void vcp_on_cdc_tx_complete(void* context) {
 
 static void vcp_on_cdc_rx(void* context) {
     UsbUartBridge* usb_uart = (UsbUartBridge*)context;
-    osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->tx_thread), WorkerEvtCdcRx);
+    furi_thread_flags_set(furi_thread_get_id(usb_uart->tx_thread), WorkerEvtCdcRx);
 }
 
 static void vcp_state_callback(void* context, uint8_t state) {
@@ -325,13 +327,13 @@ static void vcp_state_callback(void* context, uint8_t state) {
 static void vcp_on_cdc_control_line(void* context, uint8_t state) {
     UNUSED(state);
     UsbUartBridge* usb_uart = (UsbUartBridge*)context;
-    osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->thread), WorkerEvtCtrlLineSet);
+    furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtCtrlLineSet);
 }
 
 static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config) {
     UNUSED(config);
     UsbUartBridge* usb_uart = (UsbUartBridge*)context;
-    osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->thread), WorkerEvtLineCfgSet);
+    furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtLineCfgSet);
 }
 
 UsbUartBridge* usb_uart_enable(UsbUartConfig* cfg) {
@@ -351,7 +353,7 @@ UsbUartBridge* usb_uart_enable(UsbUartConfig* cfg) {
 
 void usb_uart_disable(UsbUartBridge* usb_uart) {
     furi_assert(usb_uart);
-    osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->thread), WorkerEvtStop);
+    furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtStop);
     furi_thread_join(usb_uart->thread);
     furi_thread_free(usb_uart->thread);
     free(usb_uart);
@@ -361,7 +363,7 @@ void usb_uart_set_config(UsbUartBridge* usb_uart, UsbUartConfig* cfg) {
     furi_assert(usb_uart);
     furi_assert(cfg);
     memcpy(&(usb_uart->cfg_new), cfg, sizeof(UsbUartConfig));
-    osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->thread), WorkerEvtCfgChange);
+    furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtCfgChange);
 }
 
 void usb_uart_get_config(UsbUartBridge* usb_uart, UsbUartConfig* cfg) {

+ 6 - 5
applications/gui/gui.c

@@ -19,7 +19,7 @@ ViewPort* gui_view_port_find_enabled(ViewPortArray_t array) {
 
 void gui_update(Gui* gui) {
     furi_assert(gui);
-    osThreadFlagsSet(gui->thread, GUI_THREAD_FLAG_DRAW);
+    furi_thread_flags_set(gui->thread_id, GUI_THREAD_FLAG_DRAW);
 }
 
 void gui_input_events_callback(const void* value, void* ctx) {
@@ -29,7 +29,7 @@ void gui_input_events_callback(const void* value, void* ctx) {
     Gui* gui = ctx;
 
     osMessageQueuePut(gui->input_queue, value, 0, osWaitForever);
-    osThreadFlagsSet(gui->thread, GUI_THREAD_FLAG_INPUT);
+    furi_thread_flags_set(gui->thread_id, GUI_THREAD_FLAG_INPUT);
 }
 
 // Only Fullscreen supports vertical display for now
@@ -471,7 +471,7 @@ void gui_set_lockdown(Gui* gui, bool lockdown) {
 Gui* gui_alloc() {
     Gui* gui = malloc(sizeof(Gui));
     // Thread ID
-    gui->thread = osThreadGetId();
+    gui->thread_id = furi_thread_get_current_id();
     // Allocate mutex
     gui->mutex = osMutexNew(NULL);
     furi_check(gui->mutex);
@@ -500,7 +500,8 @@ int32_t gui_srv(void* p) {
     furi_record_create("gui", gui);
 
     while(1) {
-        uint32_t flags = osThreadFlagsWait(GUI_THREAD_FLAG_ALL, osFlagsWaitAny, osWaitForever);
+        uint32_t flags =
+            furi_thread_flags_wait(GUI_THREAD_FLAG_ALL, osFlagsWaitAny, osWaitForever);
         // Process and dispatch input
         if(flags & GUI_THREAD_FLAG_INPUT) {
             // Process till queue become empty
@@ -512,7 +513,7 @@ int32_t gui_srv(void* p) {
         // Process and dispatch draw call
         if(flags & GUI_THREAD_FLAG_DRAW) {
             // Clear flags that arrived on input step
-            osThreadFlagsClear(GUI_THREAD_FLAG_DRAW);
+            furi_thread_flags_clear(GUI_THREAD_FLAG_DRAW);
             gui_redraw(gui);
         }
     }

+ 1 - 1
applications/gui/gui_i.h

@@ -57,7 +57,7 @@ ALGO_DEF(CanvasCallbackPairArray, CanvasCallbackPairArray_t);
 /** Gui structure */
 struct Gui {
     // Thread and lock
-    osThreadId_t thread;
+    FuriThreadId thread_id;
     osMutexId_t mutex;
 
     // Layers and Canvas

+ 9 - 9
applications/gui/modules/file_browser_worker.c

@@ -259,10 +259,10 @@ static int32_t browser_worker(void* context) {
     string_t filename;
     string_init(filename);
 
-    osThreadFlagsSet(furi_thread_get_thread_id(browser->thread), WorkerEvtConfigChange);
+    furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtConfigChange);
 
     while(1) {
-        uint32_t flags = osThreadFlagsWait(WORKER_FLAGS_ALL, osFlagsWaitAny, osWaitForever);
+        uint32_t flags = furi_thread_flags_wait(WORKER_FLAGS_ALL, osFlagsWaitAny, osWaitForever);
         furi_assert((flags & osFlagsError) == 0);
 
         if(flags & WorkerEvtConfigChange) {
@@ -272,7 +272,7 @@ static int32_t browser_worker(void* context) {
             }
             idx_last_array_reset(browser->idx_last);
 
-            osThreadFlagsSet(furi_thread_get_thread_id(browser->thread), WorkerEvtFolderEnter);
+            furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtFolderEnter);
         }
 
         if(flags & WorkerEvtFolderEnter) {
@@ -369,7 +369,7 @@ BrowserWorker* file_browser_worker_alloc(string_t path, const char* filter_ext,
 void file_browser_worker_free(BrowserWorker* browser) {
     furi_assert(browser);
 
-    osThreadFlagsSet(furi_thread_get_thread_id(browser->thread), WorkerEvtStop);
+    furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtStop);
     furi_thread_join(browser->thread);
     furi_thread_free(browser->thread);
 
@@ -423,30 +423,30 @@ void file_browser_worker_set_config(
     string_set(browser->path_next, path);
     string_set_str(browser->filter_extension, filter_ext);
     browser->skip_assets = skip_assets;
-    osThreadFlagsSet(furi_thread_get_thread_id(browser->thread), WorkerEvtConfigChange);
+    furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtConfigChange);
 }
 
 void file_browser_worker_folder_enter(BrowserWorker* browser, string_t path, int32_t item_idx) {
     furi_assert(browser);
     string_set(browser->path_next, path);
     browser->item_sel_idx = item_idx;
-    osThreadFlagsSet(furi_thread_get_thread_id(browser->thread), WorkerEvtFolderEnter);
+    furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtFolderEnter);
 }
 
 void file_browser_worker_folder_exit(BrowserWorker* browser) {
     furi_assert(browser);
-    osThreadFlagsSet(furi_thread_get_thread_id(browser->thread), WorkerEvtFolderExit);
+    furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtFolderExit);
 }
 
 void file_browser_worker_folder_refresh(BrowserWorker* browser, int32_t item_idx) {
     furi_assert(browser);
     browser->item_sel_idx = item_idx;
-    osThreadFlagsSet(furi_thread_get_thread_id(browser->thread), WorkerEvtFolderRefresh);
+    furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtFolderRefresh);
 }
 
 void file_browser_worker_load(BrowserWorker* browser, uint32_t offset, uint32_t count) {
     furi_assert(browser);
     browser->load_offset = offset;
     browser->load_count = count;
-    osThreadFlagsSet(furi_thread_get_thread_id(browser->thread), WorkerEvtLoad);
+    furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtLoad);
 }

+ 3 - 3
applications/input/input.c

@@ -36,7 +36,7 @@ void input_press_timer_callback(void* arg) {
 
 void input_isr(void* _ctx) {
     UNUSED(_ctx);
-    osThreadFlagsSet(input->thread, INPUT_THREAD_FLAG_ISR);
+    furi_thread_flags_set(input->thread_id, INPUT_THREAD_FLAG_ISR);
 }
 
 const char* input_get_key_name(InputKey key) {
@@ -66,7 +66,7 @@ const char* input_get_type_name(InputType type) {
 
 int32_t input_srv() {
     input = malloc(sizeof(Input));
-    input->thread = osThreadGetId();
+    input->thread_id = furi_thread_get_current_id();
     input->event_pubsub = furi_pubsub_alloc();
     furi_record_create("input_events", input->event_pubsub);
 
@@ -129,7 +129,7 @@ int32_t input_srv() {
         if(is_changing) {
             osDelay(1);
         } else {
-            osThreadFlagsWait(INPUT_THREAD_FLAG_ISR, osFlagsWaitAny, osWaitForever);
+            furi_thread_flags_wait(INPUT_THREAD_FLAG_ISR, osFlagsWaitAny, osWaitForever);
         }
     }
 

+ 1 - 1
applications/input/input_i.h

@@ -32,7 +32,7 @@ typedef struct {
 
 /** Input state */
 typedef struct {
-    osThreadId_t thread;
+    FuriThreadId thread_id;
     FuriPubSub* event_pubsub;
     InputPinState* pin_states;
     Cli* cli;

+ 6 - 9
applications/loader/loader.c

@@ -29,13 +29,9 @@ static bool
     furi_thread_set_callback(
         loader_instance->application_thread, loader_instance->application->app);
 
-    bool result = furi_thread_start(loader_instance->application_thread);
+    furi_thread_start(loader_instance->application_thread);
 
-    if(!result) {
-        loader_instance->application = NULL;
-    }
-
-    return result;
+    return true;
 }
 
 static void loader_menu_callback(void* _ctx, uint32_t index) {
@@ -300,7 +296,7 @@ static Loader* loader_alloc() {
     UNUSED(loader_cli);
 #endif
 
-    instance->loader_thread = osThreadGetId();
+    instance->loader_thread = furi_thread_get_current_id();
 
     // Gui
     instance->gui = furi_record_open("gui");
@@ -444,7 +440,7 @@ static void loader_build_submenu() {
 
 void loader_show_menu() {
     furi_assert(loader_instance);
-    osThreadFlagsSet(loader_instance->loader_thread, LOADER_THREAD_FLAG_SHOW_MENU);
+    furi_thread_flags_set(loader_instance->loader_thread, LOADER_THREAD_FLAG_SHOW_MENU);
 }
 
 void loader_update_menu() {
@@ -474,7 +470,8 @@ int32_t loader_srv(void* p) {
 #endif
 
     while(1) {
-        uint32_t flags = osThreadFlagsWait(LOADER_THREAD_FLAG_ALL, osFlagsWaitAny, osWaitForever);
+        uint32_t flags =
+            furi_thread_flags_wait(LOADER_THREAD_FLAG_ALL, osFlagsWaitAny, osWaitForever);
         if(flags & LOADER_THREAD_FLAG_SHOW_MENU) {
             menu_set_selected_item(loader_instance->primary_menu, 0);
             view_dispatcher_switch_to_view(

+ 1 - 1
applications/loader/loader_i.h

@@ -15,7 +15,7 @@
 #include <assets_icons.h>
 
 struct Loader {
-    osThreadId_t loader_thread;
+    FuriThreadId loader_thread;
 
     const FlipperApplication* application;
     FuriThread* application_thread;

+ 4 - 4
applications/rpc/rpc.c

@@ -408,7 +408,7 @@ size_t
     furi_assert(session);
     size_t bytes_sent = xStreamBufferSend(session->stream, encoded_bytes, size, timeout);
 
-    osThreadFlagsSet(furi_thread_get_thread_id(session->thread), RpcEvtNewData);
+    furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtNewData);
 
     return bytes_sent;
 }
@@ -441,7 +441,7 @@ bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) {
         if(count == bytes_received) {
             break;
         } else {
-            flags = osThreadFlagsWait(RPC_ALL_EVENTS, osFlagsWaitAny, osWaitForever);
+            flags = furi_thread_flags_wait(RPC_ALL_EVENTS, osFlagsWaitAny, osWaitForever);
             if(flags & RpcEvtDisconnect) {
                 if(xStreamBufferIsEmpty(session->stream)) {
                     session->terminate = true;
@@ -450,7 +450,7 @@ bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) {
                     break;
                 } else {
                     /* Save disconnect flag and continue reading buffer */
-                    osThreadFlagsSet(furi_thread_get_thread_id(session->thread), RpcEvtDisconnect);
+                    furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtDisconnect);
                 }
             } else if(flags & RpcEvtNewData) {
                 // Just wake thread up
@@ -643,7 +643,7 @@ void rpc_session_close(RpcSession* session) {
     rpc_session_set_send_bytes_callback(session, NULL);
     rpc_session_set_close_callback(session, NULL);
     rpc_session_set_buffer_is_empty_callback(session, NULL);
-    osThreadFlagsSet(furi_thread_get_thread_id(session->thread), RpcEvtDisconnect);
+    furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtDisconnect);
 }
 
 int32_t rpc_srv(void* p) {

+ 5 - 7
applications/rpc/rpc_gui.c

@@ -40,8 +40,7 @@ static void
 
     memcpy(buffer, data, size);
 
-    osThreadFlagsSet(
-        furi_thread_get_thread_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagTransmit);
+    furi_thread_flags_set(furi_thread_get_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagTransmit);
 }
 
 static int32_t rpc_system_gui_screen_stream_frame_transmit_thread(void* context) {
@@ -50,7 +49,8 @@ static int32_t rpc_system_gui_screen_stream_frame_transmit_thread(void* context)
     RpcGuiSystem* rpc_gui = (RpcGuiSystem*)context;
 
     while(true) {
-        uint32_t flags = osThreadFlagsWait(RpcGuiWorkerFlagAny, osFlagsWaitAny, osWaitForever);
+        uint32_t flags =
+            furi_thread_flags_wait(RpcGuiWorkerFlagAny, osFlagsWaitAny, osWaitForever);
         if(flags & RpcGuiWorkerFlagTransmit) {
             rpc_send(rpc_gui->session, rpc_gui->transmit_frame);
         }
@@ -117,8 +117,7 @@ static void rpc_system_gui_stop_screen_stream_process(const PB_Main* request, vo
         gui_remove_framebuffer_callback(
             rpc_gui->gui, rpc_system_gui_screen_stream_frame_callback, context);
         // Stop and release worker thread
-        osThreadFlagsSet(
-            furi_thread_get_thread_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagExit);
+        furi_thread_flags_set(furi_thread_get_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagExit);
         furi_thread_join(rpc_gui->transmit_thread);
         furi_thread_free(rpc_gui->transmit_thread);
         // Release frame
@@ -367,8 +366,7 @@ void rpc_system_gui_free(void* context) {
         gui_remove_framebuffer_callback(
             rpc_gui->gui, rpc_system_gui_screen_stream_frame_callback, context);
         // Stop and release worker thread
-        osThreadFlagsSet(
-            furi_thread_get_thread_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagExit);
+        furi_thread_flags_set(furi_thread_get_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagExit);
         furi_thread_join(rpc_gui->transmit_thread);
         furi_thread_free(rpc_gui->transmit_thread);
         // Release frame

+ 3 - 1
applications/subghz/helpers/subghz_chat.c

@@ -92,7 +92,9 @@ bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency) {
         instance->worker_running = true;
         instance->last_time_rx_data = 0;
 
-        res = furi_thread_start(instance->thread);
+        furi_thread_start(instance->thread);
+
+        res = true;
     }
     return res;
 }

+ 6 - 6
applications/u2f/u2f_hid.c

@@ -72,18 +72,18 @@ static void u2f_hid_event_callback(HidU2fEvent ev, void* context) {
     U2fHid* u2f_hid = context;
 
     if(ev == HidU2fDisconnected)
-        osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtDisconnect);
+        furi_thread_flags_set(furi_thread_get_id(u2f_hid->thread), WorkerEvtDisconnect);
     else if(ev == HidU2fConnected)
-        osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtConnect);
+        furi_thread_flags_set(furi_thread_get_id(u2f_hid->thread), WorkerEvtConnect);
     else if(ev == HidU2fRequest)
-        osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtRequest);
+        furi_thread_flags_set(furi_thread_get_id(u2f_hid->thread), WorkerEvtRequest);
 }
 
 static void u2f_hid_lock_timeout_callback(void* context) {
     furi_assert(context);
     U2fHid* u2f_hid = context;
 
-    osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtUnlock);
+    furi_thread_flags_set(furi_thread_get_id(u2f_hid->thread), WorkerEvtUnlock);
 }
 
 static void u2f_hid_send_response(U2fHid* u2f_hid) {
@@ -198,7 +198,7 @@ static int32_t u2f_hid_worker(void* context) {
     furi_hal_hid_u2f_set_callback(u2f_hid_event_callback, u2f_hid);
 
     while(1) {
-        uint32_t flags = osThreadFlagsWait(
+        uint32_t flags = furi_thread_flags_wait(
             WorkerEvtStop | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtRequest,
             osFlagsWaitAny,
             osWaitForever);
@@ -292,7 +292,7 @@ U2fHid* u2f_hid_start(U2fData* u2f_inst) {
 
 void u2f_hid_stop(U2fHid* u2f_hid) {
     furi_assert(u2f_hid);
-    osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtStop);
+    furi_thread_flags_set(furi_thread_get_id(u2f_hid->thread), WorkerEvtStop);
     furi_thread_join(u2f_hid->thread);
     furi_thread_free(u2f_hid->thread);
     free(u2f_hid);

+ 0 - 88
applications/unit_tests/furi_valuemutex_test.c

@@ -40,91 +40,3 @@ void test_furi_valuemutex() {
 
     mu_check(delete_mutex(&valuemutex));
 }
-
-/*
-TEST: concurrent access
-
-1. Create holding record
-2. Open it twice
-3. Change value simultaneously in two app and check integrity
-*/
-
-// TODO this test broke because mutex in furi is not implemented
-
-typedef struct {
-    // a and b must be equal
-    uint8_t a;
-    uint8_t b;
-} ConcurrentValue;
-
-void furi_concurent_app(void* p) {
-    ValueMutex* mutex = (ValueMutex*)p;
-    if(mutex == NULL) {
-        printf("cannot open mutex\r\n");
-        osThreadExit();
-    }
-
-    for(size_t i = 0; i < 10; i++) {
-        ConcurrentValue* value = (ConcurrentValue*)acquire_mutex_block(mutex);
-
-        if(value == NULL) {
-            printf("cannot take record\r\n");
-            release_mutex(mutex, value);
-            osThreadExit();
-        }
-
-        // emulate read-modify-write broken by context switching
-        uint8_t a = value->a;
-        uint8_t b = value->b;
-        a++;
-        b++;
-        furi_hal_delay_ms(2);
-        value->a = a;
-        value->b = b;
-        release_mutex(mutex, value);
-    }
-
-    osThreadExit();
-}
-
-void test_furi_concurrent_access() {
-    // TODO: reimplement or delete test
-    return;
-    /*
-    // 1. Create holding record
-    ConcurrentValue value = {.a = 0, .b = 0};
-    ValueMutex mutex;
-    mu_check(init_mutex(&mutex, &value, sizeof(value)));
-
-    // 3. Create second app for interact with it
-    FuriApp* second_app = furiac_start(furi_concurent_app, "furi concurent app", (void*)&mutex);
-
-    // 4. multiply ConcurrentValue::a
-    for(size_t i = 0; i < 4; i++) {
-        ConcurrentValue* value = (ConcurrentValue*)acquire_mutex_block(&mutex);
-
-        if(value == NULL) {
-            release_mutex(&mutex, value);
-            mu_fail("cannot take record\r\n");
-        }
-
-        // emulate read-modify-write broken by context switching
-        uint8_t a = value->a;
-        uint8_t b = value->b;
-        a++;
-        b++;
-        value->a = a;
-        furi_hal_delay_ms(10); // this is only for test, do not add delay between take/give in prod!
-        value->b = b;
-        release_mutex(&mutex, value);
-    }
-
-    furi_hal_delay_ms(50);
-
-    mu_assert_pointers_eq(second_app->handler, NULL);
-
-    mu_assert_int_eq(value.a, value.b);
-
-    mu_check(delete_mutex(&mutex));
-    */
-}

+ 0 - 5
applications/unit_tests/minunit_test.c

@@ -33,10 +33,6 @@ MU_TEST(mu_test_furi_valuemutex) {
     test_furi_valuemutex();
 }
 
-MU_TEST(mu_test_furi_concurrent_access) {
-    test_furi_concurrent_access();
-}
-
 MU_TEST(mu_test_furi_pubsub) {
     test_furi_pubsub();
 }
@@ -55,7 +51,6 @@ MU_TEST_SUITE(test_suite) {
     // v2 tests
     MU_RUN_TEST(mu_test_furi_create_open);
     MU_RUN_TEST(mu_test_furi_valuemutex);
-    MU_RUN_TEST(mu_test_furi_concurrent_access);
     MU_RUN_TEST(mu_test_furi_pubsub);
     MU_RUN_TEST(mu_test_furi_memmgr);
 }

+ 2 - 2
applications/unit_tests/storage/storage_test.c

@@ -49,7 +49,7 @@ MU_TEST(storage_file_open_lock) {
     furi_thread_set_stack_size(locker_thread, 2048);
     furi_thread_set_context(locker_thread, semaphore);
     furi_thread_set_callback(locker_thread, storage_file_locker);
-    mu_check(furi_thread_start(locker_thread));
+    furi_thread_start(locker_thread);
 
     // wait for file lock
     osSemaphoreAcquire(semaphore, osWaitForever);
@@ -139,7 +139,7 @@ MU_TEST(storage_dir_open_lock) {
     furi_thread_set_stack_size(locker_thread, 2048);
     furi_thread_set_context(locker_thread, semaphore);
     furi_thread_set_callback(locker_thread, storage_dir_locker);
-    mu_check(furi_thread_start(locker_thread));
+    furi_thread_start(locker_thread);
 
     // wait for dir lock
     osSemaphoreAcquire(semaphore, osWaitForever);

+ 2 - 2
applications/unit_tests/subghz/subghz_test.c

@@ -75,7 +75,7 @@ static bool subghz_decoder_test(const char* path, const char* name_decoder) {
                     bool level = level_duration_get_level(level_duration);
                     uint32_t duration = level_duration_get_duration(level_duration);
                     // Yield, to load data inside the worker
-                    osThreadYield();
+                    furi_thread_yield();
                     decoder->protocol->decoder->feed(decoder, level, duration);
                 } else {
                     break;
@@ -115,7 +115,7 @@ static bool subghz_decode_random_test(const char* path) {
                 bool level = level_duration_get_level(level_duration);
                 uint32_t duration = level_duration_get_duration(level_duration);
                 // Yield, to load data inside the worker
-                osThreadYield();
+                furi_thread_yield();
                 subghz_receiver_decode(receiver_handler, level, duration);
             } else {
                 break;

+ 2 - 2
applications/updater/util/update_task.c

@@ -324,9 +324,9 @@ void update_task_set_progress_cb(UpdateTask* update_task, updateProgressCb cb, v
     update_task->status_change_cb_state = state;
 }
 
-bool update_task_start(UpdateTask* update_task) {
+void update_task_start(UpdateTask* update_task) {
     furi_assert(update_task);
-    return furi_thread_start(update_task->thread);
+    furi_thread_start(update_task->thread);
 }
 
 bool update_task_is_running(UpdateTask* update_task) {

+ 1 - 1
applications/updater/util/update_task.h

@@ -74,7 +74,7 @@ void update_task_free(UpdateTask* update_task);
 
 void update_task_set_progress_cb(UpdateTask* update_task, updateProgressCb cb, void* state);
 
-bool update_task_start(UpdateTask* update_task);
+void update_task_start(UpdateTask* update_task);
 
 bool update_task_is_running(UpdateTask* update_task);
 

+ 5 - 2
core/furi.h

@@ -6,16 +6,19 @@
 
 #include <cmsis_os2.h>
 
-#include <furi/common_defines.h>
 #include <furi/check.h>
+#include <furi/common_defines.h>
+#include <furi/log.h>
+#include <furi/event_flags.h>
 #include <furi/memmgr.h>
 #include <furi/memmgr_heap.h>
+#include <furi/mutex.h>
 #include <furi/pubsub.h>
 #include <furi/record.h>
+#include <furi/semaphore.h>
 #include <furi/stdglue.h>
 #include <furi/thread.h>
 #include <furi/valuemutex.h>
-#include <furi/log.h>
 
 #include <furi_hal_gpio.h>
 

+ 45 - 0
core/furi/base.h

@@ -0,0 +1,45 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+// FreeRTOS part
+#include <FreeRTOS.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Timeout value.
+#define osWaitForever 0xFFFFFFFFU ///< Wait forever timeout value.
+
+// Flags options (\ref furi_thread_flags_wait 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).
+
+/// 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;
+
+#ifdef __cplusplus
+}
+#endif

+ 4 - 1
core/furi/check.c

@@ -6,11 +6,14 @@
 #include <furi_hal_rtc.h>
 #include <stdio.h>
 
+#include <FreeRTOS.h>
+#include <task.h>
+
 void __furi_print_name() {
     if(FURI_IS_ISR()) {
         furi_hal_console_puts("[ISR] ");
     } else {
-        const char* name = osThreadGetName(osThreadGetId());
+        const char* name = pcTaskGetName(xTaskGetCurrentTaskHandle());
         if(name == NULL) {
             furi_hal_console_puts("[main] ");
         } else {

+ 1 - 0
core/furi/check.h

@@ -1,4 +1,5 @@
 #pragma once
+
 #ifdef __cplusplus
 extern "C" {
 #define FURI_NORETURN [[noreturn]]

+ 222 - 0
core/furi/event_flags.c

@@ -0,0 +1,222 @@
+#include "event_flags.h"
+#include "common_defines.h"
+
+#include <event_groups.h>
+
+#define MAX_BITS_EVENT_GROUPS 24U
+#define EVENT_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_EVENT_GROUPS) - 1U))
+
+osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t* attr) {
+    EventGroupHandle_t hEventGroup;
+    int32_t mem;
+
+    hEventGroup = NULL;
+
+    if(FURI_IS_IRQ_MODE() == 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(FURI_IS_IRQ_MODE() != 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(FURI_IS_IRQ_MODE() != 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(FURI_IS_IRQ_MODE() != 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(FURI_IS_IRQ_MODE() != 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(FURI_IS_IRQ_MODE() != 0U) {
+        stat = osErrorISR;
+    } else if(hEventGroup == NULL) {
+        stat = osErrorParameter;
+    } else {
+        stat = osOK;
+        vEventGroupDelete(hEventGroup);
+    }
+#else
+    stat = osError;
+#endif
+
+    /* Return execution status */
+    return (stat);
+}

+ 63 - 0
core/furi/event_flags.h

@@ -0,0 +1,63 @@
+#pragma once
+
+#include "base.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/// 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;
+
+/// \details Event Flags ID identifies the event flags.
+typedef void* osEventFlagsId_t;
+
+/// 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);
+
+#ifdef __cplusplus
+}
+#endif

+ 1 - 0
core/furi/log.c

@@ -1,5 +1,6 @@
 #include "log.h"
 #include "check.h"
+#include "mutex.h"
 #include <cmsis_os2.h>
 #include <furi_hal.h>
 

+ 7 - 7
core/furi/memmgr_heap.c

@@ -133,7 +133,7 @@ void memmgr_heap_init() {
     MemmgrHeapThreadDict_init(memmgr_heap_thread_dict);
 }
 
-void memmgr_heap_enable_thread_trace(osThreadId_t thread_id) {
+void memmgr_heap_enable_thread_trace(FuriThreadId thread_id) {
     vTaskSuspendAll();
     {
         memmgr_heap_thread_trace_depth++;
@@ -147,7 +147,7 @@ void memmgr_heap_enable_thread_trace(osThreadId_t thread_id) {
     (void)xTaskResumeAll();
 }
 
-void memmgr_heap_disable_thread_trace(osThreadId_t thread_id) {
+void memmgr_heap_disable_thread_trace(FuriThreadId thread_id) {
     vTaskSuspendAll();
     {
         memmgr_heap_thread_trace_depth++;
@@ -158,7 +158,7 @@ void memmgr_heap_disable_thread_trace(osThreadId_t thread_id) {
     (void)xTaskResumeAll();
 }
 
-size_t memmgr_heap_get_thread_memory(osThreadId_t thread_id) {
+size_t memmgr_heap_get_thread_memory(FuriThreadId thread_id) {
     size_t leftovers = MEMMGR_HEAP_UNKNOWN;
     vTaskSuspendAll();
     {
@@ -192,7 +192,7 @@ size_t memmgr_heap_get_thread_memory(osThreadId_t thread_id) {
 
 #undef traceMALLOC
 static inline void traceMALLOC(void* pointer, size_t size) {
-    osThreadId_t thread_id = osThreadGetId();
+    FuriThreadId thread_id = furi_thread_get_current_id();
     if(thread_id && memmgr_heap_thread_trace_depth == 0) {
         memmgr_heap_thread_trace_depth++;
         MemmgrHeapAllocDict_t* alloc_dict =
@@ -207,7 +207,7 @@ static inline void traceMALLOC(void* pointer, size_t size) {
 #undef traceFREE
 static inline void traceFREE(void* pointer, size_t size) {
     UNUSED(size);
-    osThreadId_t thread_id = osThreadGetId();
+    FuriThreadId thread_id = furi_thread_get_current_id();
     if(thread_id && memmgr_heap_thread_trace_depth == 0) {
         memmgr_heap_thread_trace_depth++;
         MemmgrHeapAllocDict_t* alloc_dict =
@@ -297,7 +297,7 @@ static void print_heap_init() {
 
 static void print_heap_malloc(void* ptr, size_t size) {
     char tmp_str[33];
-    const char* name = osThreadGetName(osThreadGetId());
+    const char* name = furi_thread_get_name(furi_thread_get_current_id());
     if(!name) {
         name = "";
     }
@@ -318,7 +318,7 @@ static void print_heap_malloc(void* ptr, size_t size) {
 
 static void print_heap_free(void* ptr) {
     char tmp_str[33];
-    const char* name = osThreadGetName(osThreadGetId());
+    const char* name = furi_thread_get_name(furi_thread_get_current_id());
     if(!name) {
         name = "";
     }

+ 4 - 4
core/furi/memmgr_heap.h

@@ -6,7 +6,7 @@
 #pragma once
 
 #include <stdint.h>
-#include <cmsis_os2.h>
+#include "furi/thread.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -18,13 +18,13 @@ extern "C" {
  *
  * @param      thread_id  - thread id to track
  */
-void memmgr_heap_enable_thread_trace(osThreadId_t thread_id);
+void memmgr_heap_enable_thread_trace(FuriThreadId taks_handle);
 
 /** Memmgr heap disable thread allocation tracking
  *
  * @param      thread_id  - thread id to track
  */
-void memmgr_heap_disable_thread_trace(osThreadId_t thread_id);
+void memmgr_heap_disable_thread_trace(FuriThreadId taks_handle);
 
 /** Memmgr heap get allocatred thread memory
  *
@@ -32,7 +32,7 @@ void memmgr_heap_disable_thread_trace(osThreadId_t thread_id);
  *
  * @return     bytes allocated right now
  */
-size_t memmgr_heap_get_thread_memory(osThreadId_t thread_id);
+size_t memmgr_heap_get_thread_memory(FuriThreadId taks_handle);
 
 /** Memmgr heap get the max contiguous block size on the heap
  *

+ 217 - 0
core/furi/mutex.c

@@ -0,0 +1,217 @@
+#include "mutex.h"
+#include "check.h"
+#include "common_defines.h"
+
+#include <semphr.h>
+
+osMutexId_t osMutexNew(const osMutexAttr_t* attr) {
+    SemaphoreHandle_t hMutex;
+    uint32_t type;
+    uint32_t rmtx;
+    int32_t mem;
+
+    hMutex = NULL;
+
+    if(FURI_IS_IRQ_MODE() == 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(FURI_IS_IRQ_MODE() != 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(FURI_IS_IRQ_MODE() != 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.
+*/
+FuriThreadId osMutexGetOwner(osMutexId_t mutex_id) {
+    SemaphoreHandle_t hMutex;
+    FuriThreadId owner;
+
+    hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
+
+    if((FURI_IS_IRQ_MODE() != 0U) || (hMutex == NULL)) {
+        owner = 0;
+    } else {
+        owner = (FuriThreadId)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(FURI_IS_IRQ_MODE() != 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);
+}

+ 56 - 0
core/furi/mutex.h

@@ -0,0 +1,56 @@
+#pragma once
+
+#include "base.h"
+#include "thread.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Mutex attributes (attr_bits in \ref osMutexAttr_t).
+#define osMutexRecursive 0x00000001U ///< Recursive mutex.
+#define osMutexPrioInherit 0x00000002U ///< Priority inherit protocol.
+#define osMutexRobust 0x00000008U ///< Robust mutex.
+
+/// 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;
+
+/// \details Mutex ID identifies the mutex.
+typedef void* osMutexId_t;
+
+/// 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);
+
+/// 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);
+
+FuriThreadId osMutexGetOwner(osMutexId_t mutex_id);
+
+#ifdef __cplusplus
+}
+#endif

+ 1 - 1
core/furi/pubsub.c

@@ -1,9 +1,9 @@
 #include "pubsub.h"
 #include "memmgr.h"
 #include "check.h"
+#include "mutex.h"
 
 #include <m-list.h>
-#include <cmsis_os2.h>
 
 struct FuriPubSubSubscription {
     FuriPubSubCallback callback;

+ 2 - 1
core/furi/record.c

@@ -1,8 +1,9 @@
 #include "record.h"
 #include "check.h"
 #include "memmgr.h"
+#include "mutex.h"
+#include "event_flags.h"
 
-#include <cmsis_os2.h>
 #include <m-string.h>
 #include <m-dict.h>
 

+ 190 - 0
core/furi/semaphore.c

@@ -0,0 +1,190 @@
+#include "semaphore.h"
+#include "check.h"
+#include "common_defines.h"
+
+#include <semphr.h>
+
+osSemaphoreId_t
+    osSemaphoreNew(uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t* attr) {
+    SemaphoreHandle_t hSemaphore;
+    int32_t mem;
+
+    hSemaphore = NULL;
+
+    if((FURI_IS_IRQ_MODE() == 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(FURI_IS_IRQ_MODE() != 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(FURI_IS_IRQ_MODE() != 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(FURI_IS_IRQ_MODE() != 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(FURI_IS_IRQ_MODE() != 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);
+}

+ 57 - 0
core/furi/semaphore.h

@@ -0,0 +1,57 @@
+#pragma once
+
+#include "base.h"
+#include "thread.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/// 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;
+
+/// \details Semaphore ID identifies the semaphore.
+typedef void* osSemaphoreId_t;
+
+/// 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);
+
+#ifdef __cplusplus
+}
+#endif

+ 7 - 7
core/furi/stdglue.c

@@ -26,13 +26,13 @@ static ssize_t stdout_write(void* _cookie, const char* data, size_t size) {
     furi_assert(furi_stdglue);
     bool consumed = false;
     osKernelState_t state = osKernelGetState();
-    osThreadId_t thread_id = osThreadGetId();
-    if(state == osKernelRunning && thread_id &&
+    FuriThreadId task_id = furi_thread_get_current_id();
+    if(state == osKernelRunning && task_id &&
        osMutexAcquire(furi_stdglue->mutex, osWaitForever) == osOK) {
         // We are in the thread context
         // Handle thread callbacks
         FuriStdglueWriteCallback* callback_ptr =
-            FuriStdglueCallbackDict_get(furi_stdglue->thread_outputs, (uint32_t)thread_id);
+            FuriStdglueCallbackDict_get(furi_stdglue->thread_outputs, (uint32_t)task_id);
         if(callback_ptr) {
             (*callback_ptr)(_cookie, data, size);
             consumed = true;
@@ -76,14 +76,14 @@ void furi_stdglue_init() {
 
 bool furi_stdglue_set_thread_stdout_callback(FuriStdglueWriteCallback callback) {
     furi_assert(furi_stdglue);
-    osThreadId_t thread_id = osThreadGetId();
-    if(thread_id) {
+    FuriThreadId task_id = furi_thread_get_current_id();
+    if(task_id) {
         furi_check(osMutexAcquire(furi_stdglue->mutex, osWaitForever) == osOK);
         if(callback) {
             FuriStdglueCallbackDict_set_at(
-                furi_stdglue->thread_outputs, (uint32_t)thread_id, callback);
+                furi_stdglue->thread_outputs, (uint32_t)task_id, callback);
         } else {
-            FuriStdglueCallbackDict_erase(furi_stdglue->thread_outputs, (uint32_t)thread_id);
+            FuriStdglueCallbackDict_erase(furi_stdglue->thread_outputs, (uint32_t)task_id);
         }
         furi_check(osMutexRelease(furi_stdglue->mutex) == osOK);
         return true;

+ 260 - 33
core/furi/thread.c

@@ -2,7 +2,9 @@
 #include "memmgr.h"
 #include "memmgr_heap.h"
 #include "check.h"
+#include "common_defines.h"
 
+#include <task.h>
 #include <m-string.h>
 
 struct FuriThread {
@@ -15,14 +17,22 @@ struct FuriThread {
     FuriThreadStateCallback state_callback;
     void* state_context;
 
-    osThreadAttr_t attr;
-    volatile osThreadId_t id;
+    char* name;
+    configSTACK_DEPTH_TYPE stack_size;
+    FuriThreadPriority priority;
 
+    TaskHandle_t task_handle;
     bool heap_trace_enabled;
     size_t heap_size;
 };
 
-void furi_thread_set_state(FuriThread* thread, FuriThreadState state) {
+/** Catch threads that are trying to exit wrong way */
+__attribute__((__noreturn__)) void furi_thread_catch() {
+    asm volatile("nop"); // extra magic
+    furi_crash("You are doing it wrong");
+}
+
+static void furi_thread_set_state(FuriThread* thread, FuriThreadState state) {
     furi_assert(thread);
     thread->state = state;
     if(thread->state_callback) {
@@ -37,23 +47,24 @@ static void furi_thread_body(void* context) {
     furi_assert(thread->state == FuriThreadStateStarting);
     furi_thread_set_state(thread, FuriThreadStateRunning);
 
-    osThreadId_t thread_id = osThreadGetId();
+    TaskHandle_t task_handle = xTaskGetCurrentTaskHandle();
     if(thread->heap_trace_enabled == true) {
-        memmgr_heap_enable_thread_trace(thread_id);
+        memmgr_heap_enable_thread_trace((FuriThreadId)task_handle);
     }
 
     thread->ret = thread->callback(thread->context);
 
     if(thread->heap_trace_enabled == true) {
         osDelay(33);
-        thread->heap_size = memmgr_heap_get_thread_memory(thread_id);
-        memmgr_heap_disable_thread_trace(thread_id);
+        thread->heap_size = memmgr_heap_get_thread_memory((FuriThreadId)task_handle);
+        memmgr_heap_disable_thread_trace((FuriThreadId)task_handle);
     }
 
     furi_assert(thread->state == FuriThreadStateRunning);
     furi_thread_set_state(thread, FuriThreadStateStopped);
 
-    osThreadExit();
+    vTaskDelete(thread->task_handle);
+    furi_thread_catch();
 }
 
 FuriThread* furi_thread_alloc() {
@@ -66,21 +77,22 @@ void furi_thread_free(FuriThread* thread) {
     furi_assert(thread);
     furi_assert(thread->state == FuriThreadStateStopped);
 
-    if(thread->attr.name) free((void*)thread->attr.name);
+    if(thread->name) free((void*)thread->name);
     free(thread);
 }
 
 void furi_thread_set_name(FuriThread* thread, const char* name) {
     furi_assert(thread);
     furi_assert(thread->state == FuriThreadStateStopped);
-    if(thread->attr.name) free((void*)thread->attr.name);
-    thread->attr.name = strdup(name);
+    if(thread->name) free((void*)thread->name);
+    thread->name = strdup(name);
 }
 
 void furi_thread_set_stack_size(FuriThread* thread, size_t stack_size) {
     furi_assert(thread);
     furi_assert(thread->state == FuriThreadStateStopped);
-    thread->attr.stack_size = stack_size;
+    furi_assert(stack_size % 4 == 0);
+    thread->stack_size = stack_size;
 }
 
 void furi_thread_set_callback(FuriThread* thread, FuriThreadCallback callback) {
@@ -95,6 +107,13 @@ void furi_thread_set_context(FuriThread* thread, void* context) {
     thread->context = context;
 }
 
+void furi_thread_set_priority(FuriThread* thread, FuriThreadPriority priority) {
+    furi_assert(thread);
+    furi_assert(thread->state == FuriThreadStateStopped);
+    furi_assert(priority >= FuriThreadPriorityIdle && priority <= FuriThreadPriorityIsr);
+    thread->priority = priority;
+}
+
 void furi_thread_set_state_callback(FuriThread* thread, FuriThreadStateCallback callback) {
     furi_assert(thread);
     furi_assert(thread->state == FuriThreadStateStopped);
@@ -112,41 +131,39 @@ FuriThreadState furi_thread_get_state(FuriThread* thread) {
     return thread->state;
 }
 
-bool furi_thread_start(FuriThread* thread) {
+void furi_thread_start(FuriThread* thread) {
     furi_assert(thread);
     furi_assert(thread->callback);
     furi_assert(thread->state == FuriThreadStateStopped);
-    furi_assert(thread->attr.stack_size > 0);
+    furi_assert(thread->stack_size > 0 && thread->stack_size < 0xFFFF * 4);
+
     furi_thread_set_state(thread, FuriThreadStateStarting);
-    thread->id = osThreadNew(furi_thread_body, thread, &thread->attr);
-    if(thread->id) {
-        return true;
-    } else {
-        furi_assert(thread->state == FuriThreadStateStarting);
-        furi_thread_set_state(thread, FuriThreadStateStopped);
-        return false;
-    }
-}
 
-osStatus_t furi_thread_terminate(FuriThread* thread) {
-    furi_assert(thread);
-    osStatus_t ret = osThreadTerminate(thread->id);
-    if(ret == osOK) {
-        furi_thread_set_state(thread, FuriThreadStateStopped);
-    }
-    return ret;
+    BaseType_t ret = xTaskCreate(
+        furi_thread_body,
+        thread->name,
+        thread->stack_size / 4,
+        thread,
+        thread->priority ? thread->priority : FuriThreadPriorityNormal,
+        &thread->task_handle);
+
+    furi_check(ret == pdPASS);
+    furi_check(thread->task_handle);
 }
 
-osStatus_t furi_thread_join(FuriThread* thread) {
+bool furi_thread_join(FuriThread* thread) {
     furi_assert(thread);
+
     while(thread->state != FuriThreadStateStopped) {
         osDelay(10);
     }
+
     return osOK;
 }
 
-osThreadId_t furi_thread_get_thread_id(FuriThread* thread) {
-    return thread->id;
+FuriThreadId furi_thread_get_id(FuriThread* thread) {
+    furi_assert(thread);
+    return thread->task_handle;
 }
 
 void furi_thread_enable_heap_trace(FuriThread* thread) {
@@ -174,3 +191,213 @@ int32_t furi_thread_get_return_code(FuriThread* thread) {
     furi_assert(thread->state == FuriThreadStateStopped);
     return thread->ret;
 }
+
+FuriThreadId furi_thread_get_current_id() {
+    return xTaskGetCurrentTaskHandle();
+}
+
+void furi_thread_yield() {
+    furi_assert(!FURI_IS_IRQ_MODE());
+    taskYIELD();
+}
+
+/* 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))
+
+uint32_t furi_thread_flags_set(FuriThreadId 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(FURI_IS_IRQ_MODE()) {
+            yield = pdFALSE;
+
+            (void)xTaskNotifyFromISR(hTask, flags, eSetBits, &yield);
+            (void)xTaskNotifyAndQueryFromISR(hTask, 0, eNoAction, &rflags, NULL);
+
+            portYIELD_FROM_ISR(yield);
+        } else {
+            (void)xTaskNotify(hTask, flags, eSetBits);
+            (void)xTaskNotifyAndQuery(hTask, 0, eNoAction, &rflags);
+        }
+    }
+    /* Return flags after setting */
+    return (rflags);
+}
+
+uint32_t furi_thread_flags_clear(uint32_t flags) {
+    TaskHandle_t hTask;
+    uint32_t rflags, cflags;
+
+    if(FURI_IS_IRQ_MODE()) {
+        rflags = (uint32_t)osErrorISR;
+    } else if((flags & THREAD_FLAGS_INVALID_BITS) != 0U) {
+        rflags = (uint32_t)osErrorParameter;
+    } else {
+        hTask = xTaskGetCurrentTaskHandle();
+
+        if(xTaskNotifyAndQuery(hTask, 0, eNoAction, &cflags) == pdPASS) {
+            rflags = cflags;
+            cflags &= ~flags;
+
+            if(xTaskNotify(hTask, cflags, eSetValueWithOverwrite) != pdPASS) {
+                rflags = (uint32_t)osError;
+            }
+        } else {
+            rflags = (uint32_t)osError;
+        }
+    }
+
+    /* Return flags before clearing */
+    return (rflags);
+}
+
+uint32_t furi_thread_flags_get(void) {
+    TaskHandle_t hTask;
+    uint32_t rflags;
+
+    if(FURI_IS_IRQ_MODE()) {
+        rflags = (uint32_t)osErrorISR;
+    } else {
+        hTask = xTaskGetCurrentTaskHandle();
+
+        if(xTaskNotifyAndQuery(hTask, 0, eNoAction, &rflags) != pdPASS) {
+            rflags = (uint32_t)osError;
+        }
+    }
+
+    return (rflags);
+}
+
+uint32_t furi_thread_flags_wait(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(FURI_IS_IRQ_MODE()) {
+        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 = xTaskNotifyWait(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 > tout) {
+                    tout = 0;
+                } else {
+                    tout -= td;
+                }
+            } else {
+                if(timeout == 0) {
+                    rflags = (uint32_t)osErrorResource;
+                } else {
+                    rflags = (uint32_t)osErrorTimeout;
+                }
+            }
+        } while(rval != pdFAIL);
+    }
+
+    /* Return flags before clearing */
+    return (rflags);
+}
+
+uint32_t furi_thread_enumerate(FuriThreadId* thread_array, uint32_t array_items) {
+    uint32_t i, count;
+    TaskStatus_t* task;
+
+    if(FURI_IS_IRQ_MODE() || (thread_array == NULL) || (array_items == 0U)) {
+        count = 0U;
+    } else {
+        vTaskSuspendAll();
+
+        count = uxTaskGetNumberOfTasks();
+        task = pvPortMalloc(count * sizeof(TaskStatus_t));
+
+        if(task != NULL) {
+            count = uxTaskGetSystemState(task, count, NULL);
+
+            for(i = 0U; (i < count) && (i < array_items); i++) {
+                thread_array[i] = (FuriThreadId)task[i].xHandle;
+            }
+            count = i;
+        }
+        (void)xTaskResumeAll();
+
+        vPortFree(task);
+    }
+
+    return (count);
+}
+
+const char* furi_thread_get_name(FuriThreadId thread_id) {
+    TaskHandle_t hTask = (TaskHandle_t)thread_id;
+    const char* name;
+
+    if(FURI_IS_IRQ_MODE() || (hTask == NULL)) {
+        name = NULL;
+    } else {
+        name = pcTaskGetName(hTask);
+    }
+
+    return (name);
+}
+
+uint32_t furi_thread_get_stack_space(FuriThreadId thread_id) {
+    TaskHandle_t hTask = (TaskHandle_t)thread_id;
+    uint32_t sz;
+
+    if(FURI_IS_IRQ_MODE() || (hTask == NULL)) {
+        sz = 0U;
+    } else {
+        sz = (uint32_t)(uxTaskGetStackHighWaterMark(hTask) * sizeof(StackType_t));
+    }
+
+    return (sz);
+}

+ 56 - 21
core/furi/thread.h

@@ -5,9 +5,7 @@
 
 #pragma once
 
-#include <stdint.h>
-#include <stdbool.h>
-#include <cmsis_os2.h>
+#include "base.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -20,9 +18,24 @@ typedef enum {
     FuriThreadStateRunning,
 } FuriThreadState;
 
+/** FuriThreadPriority */
+typedef enum {
+    FuriThreadPriorityNone = 0, /**< Uninitialized, choose system default */
+    FuriThreadPriorityIdle = 1, /**< Idle priority */
+    FuriThreadPriorityLowest = 14, /**< Lowest */
+    FuriThreadPriorityLow = 15, /**< Low */
+    FuriThreadPriorityNormal = 16, /**< Normal */
+    FuriThreadPriorityHigh = 17, /**< High */
+    FuriThreadPriorityHighest = 18, /**< Highest */
+    FuriThreadPriorityIsr = 32, /**< Deffered Isr (highest possible) */
+} FuriThreadPriority;
+
 /** FuriThread anonymous structure */
 typedef struct FuriThread FuriThread;
 
+/** FuriThreadId proxy type to OS low level functions */
+typedef void* FuriThreadId;
+
 /** FuriThreadCallback Your callback to run in new thread
  * @warning    never use osThreadExit in FuriThread
  */
@@ -74,6 +87,13 @@ void furi_thread_set_callback(FuriThread* thread, FuriThreadCallback callback);
  */
 void furi_thread_set_context(FuriThread* thread, void* context);
 
+/** Set FuriThread priority
+ *
+ * @param      thread   FuriThread instance
+ * @param      priority FuriThreadPriority value
+ */
+void furi_thread_set_priority(FuriThread* thread, FuriThreadPriority priority);
+
 /** Set FuriThread state change callback
  *
  * @param      thread    FuriThread instance
@@ -99,36 +119,24 @@ FuriThreadState furi_thread_get_state(FuriThread* thread);
 /** Start FuriThread
  *
  * @param      thread  FuriThread instance
- *
- * @return     true on success
  */
-bool furi_thread_start(FuriThread* thread);
-
-/** Treminate FuriThread
- *
- * @param      thread  FuriThread instance
- *
- * @return     osStatus_t
- * @warning    terminating statefull thread is dangerous use only if you know
- *             what you doing
- */
-osStatus_t furi_thread_terminate(FuriThread* thread);
+void furi_thread_start(FuriThread* thread);
 
 /** Join FuriThread
  *
  * @param      thread  FuriThread instance
  *
- * @return     osStatus_t
+ * @return     bool
  */
-osStatus_t furi_thread_join(FuriThread* thread);
+bool furi_thread_join(FuriThread* thread);
 
-/** Get CMSIS Thread ID
+/** Get FreeRTOS FuriThreadId for FuriThread instance
  *
  * @param      thread  FuriThread instance
  *
- * @return     osThreadId_t or NULL
+ * @return     FuriThreadId or NULL
  */
-osThreadId_t furi_thread_get_thread_id(FuriThread* thread);
+FuriThreadId furi_thread_get_id(FuriThread* thread);
 
 /** Enable heap tracing
  *
@@ -158,6 +166,33 @@ size_t furi_thread_get_heap_size(FuriThread* thread);
  */
 int32_t furi_thread_get_return_code(FuriThread* thread);
 
+/** Thread releated methods that doesn't involve FuriThread directly */
+
+/** Get FreeRTOS FuriThreadId for current thread
+ *
+ * @param      thread  FuriThread instance
+ *
+ * @return     FuriThreadId or NULL
+ */
+FuriThreadId furi_thread_get_current_id();
+
+/** Return control to scheduler */
+void furi_thread_yield();
+
+uint32_t furi_thread_flags_set(FuriThreadId thread_id, uint32_t flags);
+
+uint32_t furi_thread_flags_clear(uint32_t flags);
+
+uint32_t furi_thread_flags_get(void);
+
+uint32_t furi_thread_flags_wait(uint32_t flags, uint32_t options, uint32_t timeout);
+
+uint32_t furi_thread_enumerate(FuriThreadId* thread_array, uint32_t array_items);
+
+const char* furi_thread_get_name(FuriThreadId thread_id);
+
+uint32_t furi_thread_get_stack_space(FuriThreadId thread_id);
+
 #ifdef __cplusplus
 }
 #endif

+ 1 - 0
core/furi/valuemutex.h

@@ -2,6 +2,7 @@
 
 #include <cmsis_os2.h>
 #include <stdbool.h>
+#include "mutex.h"
 
 #ifdef __cplusplus
 extern "C" {

+ 5 - 2
firmware/targets/f7/Inc/FreeRTOSConfig.h

@@ -20,7 +20,7 @@ extern uint32_t SystemCoreClock;
 #define configUSE_TICK_HOOK 0
 #define configCPU_CLOCK_HZ (SystemCoreClock)
 #define configTICK_RATE_HZ ((TickType_t)1000)
-#define configMAX_PRIORITIES (56)
+#define configMAX_PRIORITIES (32)
 #define configMINIMAL_STACK_SIZE ((uint16_t)128)
 
 /* Heap size determined automatically by linker */
@@ -35,7 +35,7 @@ extern uint32_t SystemCoreClock;
 #define configUSE_RECURSIVE_MUTEXES 1
 #define configUSE_COUNTING_SEMAPHORES 1
 #define configENABLE_BACKWARD_COMPATIBILITY 0
-#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
 #define configUSE_TICKLESS_IDLE 2
 #define configRECORD_STACK_HIGH_ADDRESS 1
 #define configUSE_NEWLIB_REENTRANT 0
@@ -89,6 +89,9 @@ to exclude the API function. */
 #define configTASK_NOTIFICATION_ARRAY_ENTRIES 2
 #define CMSIS_TASK_NOTIFY_INDEX 1
 
+extern __attribute__((__noreturn__)) void furi_thread_catch();
+#define configTASK_RETURN_ADDRESS (furi_thread_catch + 2)
+
 /*
  * The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used
  * by the application thus the correct define need to be enabled below

+ 10 - 8
firmware/targets/f7/Src/main.c

@@ -7,19 +7,16 @@
 
 #define TAG "Main"
 
-static const osThreadAttr_t init_thread_attr = {
-    .name = "Init",
-    .stack_size = 4096,
-};
+int32_t init_task(void* context) {
+    UNUSED(context);
 
-void init_task() {
     // Flipper FURI HAL
     furi_hal_init();
 
     // Init flipper
     flipper_init();
 
-    osThreadExit();
+    return 0;
 }
 
 int main() {
@@ -29,8 +26,13 @@ int main() {
     // Flipper critical FURI HAL
     furi_hal_init_early();
 
+    FuriThread* main_thread = furi_thread_alloc();
+    furi_thread_set_name(main_thread, "Init");
+    furi_thread_set_stack_size(main_thread, 4096);
+    furi_thread_set_callback(main_thread, init_task);
+
 #ifdef FURI_RAM_EXEC
-    osThreadNew(init_task, NULL, &init_thread_attr);
+    furi_thread_start(main_thread);
 #else
     furi_hal_light_sequence("RGB");
 
@@ -52,7 +54,7 @@ int main() {
         furi_hal_power_reset();
     } else {
         furi_hal_light_sequence("rgb G");
-        osThreadNew(init_task, NULL, &init_thread_attr);
+        furi_thread_start(main_thread);
     }
 #endif
 

+ 6 - 5
firmware/targets/f7/ble_glue/ble_app.c

@@ -6,6 +6,7 @@
 #include "gap.h"
 
 #include <furi_hal.h>
+#include <furi.h>
 
 #define TAG "Bt"
 
@@ -106,9 +107,9 @@ void ble_app_get_key_storage_buff(uint8_t** addr, uint16_t* size) {
 
 void ble_app_thread_stop() {
     if(ble_app) {
-        osThreadId_t thread_id = furi_thread_get_thread_id(ble_app->thread);
+        FuriThreadId thread_id = furi_thread_get_id(ble_app->thread);
         furi_assert(thread_id);
-        osThreadFlagsSet(thread_id, BLE_APP_FLAG_KILL_THREAD);
+        furi_thread_flags_set(thread_id, BLE_APP_FLAG_KILL_THREAD);
         furi_thread_join(ble_app->thread);
         furi_thread_free(ble_app->thread);
         // Free resources
@@ -125,7 +126,7 @@ static int32_t ble_app_hci_thread(void* arg) {
     uint32_t flags = 0;
 
     while(1) {
-        flags = osThreadFlagsWait(BLE_APP_FLAG_ALL, osFlagsWaitAny, osWaitForever);
+        flags = furi_thread_flags_wait(BLE_APP_FLAG_ALL, osFlagsWaitAny, osWaitForever);
         if(flags & BLE_APP_FLAG_KILL_THREAD) {
             break;
         }
@@ -141,9 +142,9 @@ static int32_t ble_app_hci_thread(void* arg) {
 void hci_notify_asynch_evt(void* pdata) {
     UNUSED(pdata);
     if(ble_app) {
-        osThreadId_t thread_id = furi_thread_get_thread_id(ble_app->thread);
+        FuriThreadId thread_id = furi_thread_get_id(ble_app->thread);
         furi_assert(thread_id);
-        osThreadFlagsSet(thread_id, BLE_APP_FLAG_HCI_EVENT);
+        furi_thread_flags_set(thread_id, BLE_APP_FLAG_HCI_EVENT);
     }
 }
 

+ 5 - 5
firmware/targets/f7/ble_glue/ble_glue.c

@@ -333,9 +333,9 @@ static void ble_glue_clear_shared_memory() {
 
 void ble_glue_thread_stop() {
     if(ble_glue) {
-        osThreadId_t thread_id = furi_thread_get_thread_id(ble_glue->thread);
+        FuriThreadId thread_id = furi_thread_get_id(ble_glue->thread);
         furi_assert(thread_id);
-        osThreadFlagsSet(thread_id, BLE_GLUE_FLAG_KILL_THREAD);
+        furi_thread_flags_set(thread_id, BLE_GLUE_FLAG_KILL_THREAD);
         furi_thread_join(ble_glue->thread);
         furi_thread_free(ble_glue->thread);
         // Free resources
@@ -353,7 +353,7 @@ static int32_t ble_glue_shci_thread(void* context) {
     uint32_t flags = 0;
 
     while(true) {
-        flags = osThreadFlagsWait(BLE_GLUE_FLAG_ALL, osFlagsWaitAny, osWaitForever);
+        flags = furi_thread_flags_wait(BLE_GLUE_FLAG_ALL, osFlagsWaitAny, osWaitForever);
         if(flags & BLE_GLUE_FLAG_SHCI_EVENT) {
             shci_user_evt_proc();
         }
@@ -368,9 +368,9 @@ static int32_t ble_glue_shci_thread(void* context) {
 void shci_notify_asynch_evt(void* pdata) {
     UNUSED(pdata);
     if(ble_glue) {
-        osThreadId_t thread_id = furi_thread_get_thread_id(ble_glue->thread);
+        FuriThreadId thread_id = furi_thread_get_id(ble_glue->thread);
         furi_assert(thread_id);
-        osThreadFlagsSet(thread_id, BLE_GLUE_FLAG_SHCI_EVENT);
+        furi_thread_flags_set(thread_id, BLE_GLUE_FLAG_SHCI_EVENT);
     }
 }
 

+ 1 - 1
firmware/targets/f7/furi_hal/furi_hal_bt.c

@@ -322,7 +322,7 @@ void furi_hal_bt_set_key_storage_change_callback(
 
 void furi_hal_bt_nvm_sram_sem_acquire() {
     while(LL_HSEM_1StepLock(HSEM, CFG_HW_BLE_NVM_SRAM_SEMID)) {
-        osThreadYield();
+        furi_thread_yield();
     }
 }
 

+ 1 - 1
firmware/targets/f7/furi_hal/furi_hal_crc.c

@@ -34,7 +34,7 @@ void furi_hal_crc_init(bool synchronize) {
 void furi_hal_crc_reset() {
     furi_check(hal_crc_control.state == CRC_State_Ready);
     if(hal_crc_control.mtx) {
-        furi_check(osMutexGetOwner(hal_crc_control.mtx) == osThreadGetId());
+        furi_check(osMutexGetOwner(hal_crc_control.mtx) == furi_thread_get_current_id());
         osMutexRelease(hal_crc_control.mtx);
     }
     LL_CRC_ResetCRCCalculationUnit(CRC);

+ 6 - 6
firmware/targets/f7/furi_hal/furi_hal_flash.c

@@ -112,7 +112,7 @@ static void furi_hal_flash_lock(void) {
 static void furi_hal_flash_begin_with_core2(bool erase_flag) {
     // Take flash controller ownership
     while(LL_HSEM_1StepLock(HSEM, CFG_HW_FLASH_SEMID) != 0) {
-        osThreadYield();
+        furi_thread_yield();
     }
 
     // Unlock flash operation
@@ -128,7 +128,7 @@ static void furi_hal_flash_begin_with_core2(bool erase_flag) {
     while(true) {
         // Wait till flash controller become usable
         while(LL_FLASH_IsActiveFlag_OperationSuspended()) {
-            osThreadYield();
+            furi_thread_yield();
         };
 
         // Just a little more love
@@ -137,14 +137,14 @@ static void furi_hal_flash_begin_with_core2(bool erase_flag) {
         // Actually we already have mutex for it, but specification is specification
         if(LL_HSEM_IsSemaphoreLocked(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID)) {
             taskEXIT_CRITICAL();
-            osThreadYield();
+            furi_thread_yield();
             continue;
         }
 
         // Take sempahopre and prevent core2 from anything funky
         if(LL_HSEM_1StepLock(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) != 0) {
             taskEXIT_CRITICAL();
-            osThreadYield();
+            furi_thread_yield();
             continue;
         }
 
@@ -173,7 +173,7 @@ static void furi_hal_flash_end_with_core2(bool erase_flag) {
 
     // Doesn't make much sense, does it?
     while(READ_BIT(FLASH->SR, FLASH_SR_BSY)) {
-        osThreadYield();
+        furi_thread_yield();
     }
 
     // Erase activity over, core2 can continue
@@ -498,7 +498,7 @@ bool furi_hal_flash_ob_set_word(size_t word_idx, const uint32_t value) {
     /* 3. Check that no Flash memory operation is on going by checking the BSY && PESD */
     furi_check(furi_hal_flash_wait_last_operation(FURI_HAL_FLASH_TIMEOUT));
     while(LL_FLASH_IsActiveFlag_OperationSuspended()) {
-        osThreadYield();
+        furi_thread_yield();
     };
 
     /* 4. Set the Options start bit OPTSTRT */

+ 3 - 3
firmware/targets/f7/furi_hal/furi_hal_nfc.c

@@ -179,7 +179,7 @@ bool furi_hal_nfc_activate_nfca(uint32_t timeout, uint32_t* cuid) {
             FURI_LOG_T(TAG, "Timeout");
             return false;
         }
-        osThreadYield();
+        furi_thread_yield();
     }
     rfalNfcGetDevicesFound(&dev_list, &dev_cnt);
     // Take first device and set cuid
@@ -397,14 +397,14 @@ static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_
     }
 
     // Manually wait for interrupt
-    furi_hal_gpio_init(&gpio_rfid_pull, GpioModeInput, GpioPullDown, GpioSpeedVeryHigh);
+    furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeInput, GpioPullDown, GpioSpeedVeryHigh);
     st25r3916ClearAndEnableInterrupts(ST25R3916_IRQ_MASK_RXE);
 
     uint32_t irq = 0;
     uint8_t rxe = 0;
     uint32_t start = DWT->CYCCNT;
     while(true) {
-        if(furi_hal_gpio_read(&gpio_rfid_pull) == true) {
+        if(furi_hal_gpio_read(&gpio_nfc_irq_rfid_pull) == true) {
             st25r3916ReadRegister(ST25R3916_REG_IRQ_MAIN, &rxe);
             if(rxe & (1 << 4)) {
                 irq = 1;

+ 2 - 2
firmware/targets/f7/furi_hal/furi_hal_resources.c

@@ -42,7 +42,7 @@ const GpioPin gpio_ext_pa4 = {.port = GPIOA, .pin = LL_GPIO_PIN_4};
 const GpioPin gpio_ext_pa6 = {.port = GPIOA, .pin = LL_GPIO_PIN_6};
 const GpioPin gpio_ext_pa7 = {.port = GPIOA, .pin = LL_GPIO_PIN_7};
 
-const GpioPin gpio_rfid_pull = {.port = RFID_PULL_GPIO_Port, .pin = RFID_PULL_Pin};
+const GpioPin gpio_nfc_irq_rfid_pull = {.port = RFID_PULL_GPIO_Port, .pin = RFID_PULL_Pin};
 const GpioPin gpio_rfid_carrier_out = {.port = RFID_OUT_GPIO_Port, .pin = RFID_OUT_Pin};
 const GpioPin gpio_rfid_data_in = {.port = RFID_RF_IN_GPIO_Port, .pin = RFID_RF_IN_Pin};
 const GpioPin gpio_rfid_carrier = {.port = RFID_CARRIER_GPIO_Port, .pin = RFID_CARRIER_Pin};
@@ -138,7 +138,7 @@ void furi_hal_resources_init() {
 
     furi_hal_gpio_init(&ibutton_gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
 
-    furi_hal_gpio_init(&gpio_rfid_pull, GpioModeInterruptRise, GpioPullNo, GpioSpeedLow);
+    furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeInterruptRise, GpioPullNo, GpioSpeedLow);
 
     furi_hal_gpio_init(&gpio_rf_sw_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
 

+ 1 - 1
firmware/targets/f7/furi_hal/furi_hal_resources.h

@@ -77,7 +77,7 @@ extern const GpioPin gpio_ext_pa4;
 extern const GpioPin gpio_ext_pa6;
 extern const GpioPin gpio_ext_pa7;
 
-extern const GpioPin gpio_rfid_pull;
+extern const GpioPin gpio_nfc_irq_rfid_pull;
 extern const GpioPin gpio_rfid_carrier_out;
 extern const GpioPin gpio_rfid_data_in;
 extern const GpioPin gpio_rfid_carrier;

+ 11 - 7
firmware/targets/f7/furi_hal/furi_hal_rfid.c

@@ -69,8 +69,8 @@ void furi_hal_rfid_pins_reset() {
     furi_hal_gpio_write(&gpio_rfid_carrier_out, false);
 
     // from both sides
-    furi_hal_gpio_init(&gpio_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
-    furi_hal_gpio_write(&gpio_rfid_pull, true);
+    furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
+    furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, true);
 
     furi_hal_gpio_init_simple(&gpio_rfid_carrier, GpioModeAnalog);
 
@@ -84,7 +84,11 @@ void furi_hal_rfid_pins_emulate() {
 
     // pull pin to timer out
     furi_hal_gpio_init_ex(
-        &gpio_rfid_pull, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2);
+        &gpio_nfc_irq_rfid_pull,
+        GpioModeAltFunctionPushPull,
+        GpioPullNo,
+        GpioSpeedLow,
+        GpioAltFn1TIM2);
 
     // pull rfid antenna from carrier side
     furi_hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
@@ -100,8 +104,8 @@ void furi_hal_rfid_pins_read() {
     furi_hal_ibutton_pin_low();
 
     // dont pull rfid antenna
-    furi_hal_gpio_init(&gpio_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
-    furi_hal_gpio_write(&gpio_rfid_pull, false);
+    furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
+    furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, false);
 
     // carrier pin to timer out
     furi_hal_gpio_init_ex(
@@ -116,11 +120,11 @@ void furi_hal_rfid_pins_read() {
 }
 
 void furi_hal_rfid_pin_pull_release() {
-    furi_hal_gpio_write(&gpio_rfid_pull, true);
+    furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, true);
 }
 
 void furi_hal_rfid_pin_pull_pulldown() {
-    furi_hal_gpio_write(&gpio_rfid_pull, false);
+    furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, false);
 }
 
 void furi_hal_rfid_tim_read(float freq, float duty_cycle) {

+ 8 - 8
firmware/targets/f7/furi_hal/furi_hal_usb.c

@@ -101,7 +101,7 @@ bool furi_hal_usb_set_config(FuriHalUsbInterface* new_if, void* ctx) {
         return true;
     }
     furi_assert(usb.thread);
-    osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventModeChange);
+    furi_thread_flags_set(furi_thread_get_id(usb.thread), EventModeChange);
     return true;
 }
 
@@ -125,17 +125,17 @@ bool furi_hal_usb_is_locked() {
 
 void furi_hal_usb_disable() {
     furi_assert(usb.thread);
-    osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventDisable);
+    furi_thread_flags_set(furi_thread_get_id(usb.thread), EventDisable);
 }
 
 void furi_hal_usb_enable() {
     furi_assert(usb.thread);
-    osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventEnable);
+    furi_thread_flags_set(furi_thread_get_id(usb.thread), EventEnable);
 }
 
 void furi_hal_usb_reinit() {
     furi_assert(usb.thread);
-    osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventReinit);
+    furi_thread_flags_set(furi_thread_get_id(usb.thread), EventReinit);
 }
 
 /* Get device / configuration descriptors */
@@ -148,7 +148,7 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_
 
     switch(dtype) {
     case USB_DTYPE_DEVICE:
-        osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventRequest);
+        furi_thread_flags_set(furi_thread_get_id(usb.thread), EventRequest);
         if(usb.callback != NULL) {
             usb.callback(FuriHalUsbStateEventDescriptorRequest, usb.cb_ctx);
         }
@@ -192,7 +192,7 @@ static void reset_evt(usbd_device* dev, uint8_t event, uint8_t ep) {
     UNUSED(dev);
     UNUSED(event);
     UNUSED(ep);
-    osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventReset);
+    furi_thread_flags_set(furi_thread_get_id(usb.thread), EventReset);
     if(usb.callback != NULL) {
         usb.callback(FuriHalUsbStateEventReset, usb.cb_ctx);
     }
@@ -236,11 +236,11 @@ static int32_t furi_hal_usb_thread(void* context) {
     FuriHalUsbInterface* if_ctx_new = NULL;
 
     if(usb.if_next != NULL) {
-        osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventModeChange);
+        furi_thread_flags_set(furi_thread_get_id(usb.thread), EventModeChange);
     }
 
     while(true) {
-        uint32_t flags = osThreadFlagsWait(USB_SRV_ALL_EVENTS, osFlagsWaitAny, 500);
+        uint32_t flags = furi_thread_flags_wait(USB_SRV_ALL_EVENTS, osFlagsWaitAny, 500);
         if((flags & osFlagsError) == 0) {
             if(flags & EventModeChange) {
                 if(usb.if_next != usb.if_cur) {

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 80 - 1092
lib/FreeRTOS-glue/cmsis_os2.c


+ 59 - 513
lib/FreeRTOS-glue/cmsis_os2.h

@@ -43,10 +43,10 @@
  * 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)
@@ -60,24 +60,23 @@
 #define __NO_RETURN
 #endif
 #endif
- 
-#include <stdint.h>
-#include <stddef.h>
- 
+
+#include <furi/base.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.
@@ -88,167 +87,31 @@ typedef enum {
   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
@@ -256,41 +119,7 @@ typedef struct {
   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
@@ -298,196 +127,79 @@ typedef struct {
   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 
+  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.
@@ -495,213 +207,47 @@ osStatus_t osDelayUntil (uint32_t ticks);
 /// \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.
@@ -709,7 +255,7 @@ const char *osMessageQueueGetName (osMessageQueueId_t mq_id);
 /// \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.
@@ -717,40 +263,40 @@ osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uin
 /// \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_

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

@@ -1,63 +0,0 @@
-/* --------------------------------------------------------------------------
- * 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_ */

+ 7 - 24
lib/FreeRTOS-glue/freertos_os2.h

@@ -75,7 +75,7 @@
 #endif
 
 /*
-  Option to exclude CMSIS-RTOS2 function osThreadEnumerate from the application image.
+  Option to exclude CMSIS-RTOS2 function furi_thread_enumerate from the application image.
 */
 #ifndef configUSE_OS2_THREAD_ENUMERATE
 #define configUSE_OS2_THREAD_ENUMERATE        1
@@ -153,7 +153,7 @@
 #if (INCLUDE_xTaskGetCurrentTaskHandle == 0)
   /*
     CMSIS-RTOS2 API uses FreeRTOS function xTaskGetCurrentTaskHandle to implement
-    functions osThreadGetId, osThreadFlagsClear and osThreadFlagsGet. In case if these
+    functions osThreadGetId, furi_thread_flags_clear and furi_thread_flags_get. 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.
   */
@@ -170,8 +170,8 @@
 #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
+    CMSIS-RTOS2 function furi_thread_get_stack_space uses FreeRTOS function uxTaskGetStackHighWaterMark.
+    In case if furi_thread_get_stack_space is not used in the application image, compiler will
     optimize it away.
     Set #define INCLUDE_uxTaskGetStackHighWaterMark 1 to fix this error.
   */
@@ -294,16 +294,16 @@
 
 #if (configUSE_TRACE_FACILITY == 0)
   /*
-    CMSIS-RTOS2 function osThreadEnumerate requires FreeRTOS function uxTaskGetSystemState
+    CMSIS-RTOS2 function furi_thread_enumerate 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
+    Alternatively, if the application does not use furi_thread_enumerate 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."
+    #error "Definition configUSE_TRACE_FACILITY must equal 1 to implement furi_thread_enumerate."
   #endif
 #endif
 
@@ -316,21 +316,4 @@
   #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_ */

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

@@ -1,80 +0,0 @@
-/**************************************************************************//**
- * @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 */

+ 30 - 21
lib/ST25RFAL002/platform.c

@@ -3,49 +3,58 @@
 #include <furi.h>
 #include <furi_hal_spi.h>
 
-static const osThreadAttr_t platform_irq_thread_attr = {
-    .name = "RfalIrqDriver",
-    .stack_size = 1024,
-    .priority = osPriorityRealtime,
-};
+typedef struct {
+    FuriThread* thread;
+    volatile PlatformIrqCallback callback;
+} RfalPlatform;
 
-static volatile osThreadId_t platform_irq_thread_id = NULL;
-static volatile PlatformIrqCallback platform_irq_callback = NULL;
-static const GpioPin pin = {ST25R_INT_PORT, ST25R_INT_PIN};
+static volatile RfalPlatform rfal_platform = {
+    .thread = NULL,
+    .callback = NULL,
+};
 
 void nfc_isr(void* _ctx) {
     UNUSED(_ctx);
-    if(platform_irq_callback && platformGpioIsHigh(ST25R_INT_PORT, ST25R_INT_PIN)) {
-        osThreadFlagsSet(platform_irq_thread_id, 0x1);
+    if(rfal_platform.callback && platformGpioIsHigh(ST25R_INT_PORT, ST25R_INT_PIN)) {
+        furi_thread_flags_set(furi_thread_get_id(rfal_platform.thread), 0x1);
     }
 }
 
-void platformIrqThread() {
+int32_t rfal_platform_irq_thread(void* context) {
+    UNUSED(context);
+
     while(1) {
-        uint32_t flags = osThreadFlagsWait(0x1, osFlagsWaitAny, osWaitForever);
+        uint32_t flags = furi_thread_flags_wait(0x1, osFlagsWaitAny, osWaitForever);
         if(flags & 0x1) {
-            platform_irq_callback();
+            rfal_platform.callback();
         }
     }
 }
 
 void platformEnableIrqCallback() {
-    furi_hal_gpio_init(&pin, GpioModeInterruptRise, GpioPullDown, GpioSpeedLow);
-    furi_hal_gpio_enable_int_callback(&pin);
+    furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeInterruptRise, GpioPullDown, GpioSpeedLow);
+    furi_hal_gpio_enable_int_callback(&gpio_nfc_irq_rfid_pull);
 }
 
 void platformDisableIrqCallback() {
-    furi_hal_gpio_init(&pin, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
-    furi_hal_gpio_disable_int_callback(&pin);
+    furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
+    furi_hal_gpio_disable_int_callback(&gpio_nfc_irq_rfid_pull);
 }
 
 void platformSetIrqCallback(PlatformIrqCallback callback) {
-    platform_irq_callback = callback;
-    platform_irq_thread_id = osThreadNew(platformIrqThread, NULL, &platform_irq_thread_attr);
-    furi_hal_gpio_add_int_callback(&pin, nfc_isr, NULL);
+    rfal_platform.callback = callback;
+    rfal_platform.thread = furi_thread_alloc();
+
+    furi_thread_set_name(rfal_platform.thread, "RfalIrqDriver");
+    furi_thread_set_callback(rfal_platform.thread, rfal_platform_irq_thread);
+    furi_thread_set_stack_size(rfal_platform.thread, 1024);
+    furi_thread_set_priority(rfal_platform.thread, FuriThreadPriorityIsr);
+    furi_thread_start(rfal_platform.thread);
+
+    furi_hal_gpio_add_int_callback(&gpio_nfc_irq_rfid_pull, nfc_isr, NULL);
     // Disable interrupt callback as the pin is shared between 2 apps
     // It is enabled in rfalLowPowerModeStop()
-    furi_hal_gpio_disable_int_callback(&pin);
+    furi_hal_gpio_disable_int_callback(&gpio_nfc_irq_rfid_pull);
 }
 
 bool platformSpiTxRx(const uint8_t* txBuf, uint8_t* rxBuf, uint16_t len) {

+ 14 - 14
lib/infrared/worker/infrared_worker.c

@@ -92,8 +92,8 @@ static void infrared_worker_furi_hal_message_sent_isr_callback(void* context);
 
 static void infrared_worker_rx_timeout_callback(void* context) {
     InfraredWorker* instance = context;
-    uint32_t flags_set = osThreadFlagsSet(
-        furi_thread_get_thread_id(instance->thread), INFRARED_WORKER_RX_TIMEOUT_RECEIVED);
+    uint32_t flags_set = furi_thread_flags_set(
+        furi_thread_get_id(instance->thread), INFRARED_WORKER_RX_TIMEOUT_RECEIVED);
     furi_check(flags_set & INFRARED_WORKER_RX_TIMEOUT_RECEIVED);
 }
 
@@ -110,7 +110,7 @@ static void infrared_worker_rx_callback(void* context, bool level, uint32_t dura
                                                        INFRARED_WORKER_OVERRUN;
     portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
 
-    uint32_t flags_set = osThreadFlagsSet(furi_thread_get_thread_id(instance->thread), events);
+    uint32_t flags_set = furi_thread_flags_set(furi_thread_get_id(instance->thread), events);
     furi_check(flags_set & events);
 }
 
@@ -152,8 +152,8 @@ static void
             instance->signal.timings[instance->signal.timings_cnt] = duration;
             ++instance->signal.timings_cnt;
         } else {
-            uint32_t flags_set = osThreadFlagsSet(
-                furi_thread_get_thread_id(instance->thread), INFRARED_WORKER_OVERRUN);
+            uint32_t flags_set = furi_thread_flags_set(
+                furi_thread_get_id(instance->thread), INFRARED_WORKER_OVERRUN);
             furi_check(flags_set & INFRARED_WORKER_OVERRUN);
             instance->rx.overrun = true;
         }
@@ -167,7 +167,7 @@ static int32_t infrared_worker_rx_thread(void* thread_context) {
     TickType_t last_blink_time = 0;
 
     while(1) {
-        events = osThreadFlagsWait(INFRARED_WORKER_ALL_RX_EVENTS, 0, osWaitForever);
+        events = furi_thread_flags_wait(INFRARED_WORKER_ALL_RX_EVENTS, 0, osWaitForever);
         furi_check(events & INFRARED_WORKER_ALL_RX_EVENTS); /* at least one caught */
 
         if(events & INFRARED_WORKER_RX_RECEIVED) {
@@ -282,7 +282,7 @@ void infrared_worker_rx_stop(InfraredWorker* instance) {
     furi_hal_infrared_async_rx_set_capture_isr_callback(NULL, NULL);
     furi_hal_infrared_async_rx_stop();
 
-    osThreadFlagsSet(furi_thread_get_thread_id(instance->thread), INFRARED_WORKER_EXIT);
+    furi_thread_flags_set(furi_thread_get_id(instance->thread), INFRARED_WORKER_EXIT);
     furi_thread_join(instance->thread);
 
     BaseType_t xReturn = xStreamBufferReset(instance->stream);
@@ -342,8 +342,8 @@ void infrared_worker_tx_start(InfraredWorker* instance) {
 
 static void infrared_worker_furi_hal_message_sent_isr_callback(void* context) {
     InfraredWorker* instance = context;
-    uint32_t flags_set = osThreadFlagsSet(
-        furi_thread_get_thread_id(instance->thread), INFRARED_WORKER_TX_MESSAGE_SENT);
+    uint32_t flags_set = furi_thread_flags_set(
+        furi_thread_get_id(instance->thread), INFRARED_WORKER_TX_MESSAGE_SENT);
     furi_check(flags_set & INFRARED_WORKER_TX_MESSAGE_SENT);
 }
 
@@ -369,8 +369,8 @@ static FuriHalInfraredTxGetDataState
         state = FuriHalInfraredTxGetDataStateDone;
     }
 
-    uint32_t flags_set = osThreadFlagsSet(
-        furi_thread_get_thread_id(instance->thread), INFRARED_WORKER_TX_FILL_BUFFER);
+    uint32_t flags_set = furi_thread_flags_set(
+        furi_thread_get_id(instance->thread), INFRARED_WORKER_TX_FILL_BUFFER);
     furi_check(flags_set & INFRARED_WORKER_TX_FILL_BUFFER);
 
     return state;
@@ -498,7 +498,7 @@ static int32_t infrared_worker_tx_thread(void* thread_context) {
             furi_hal_infrared_async_tx_wait_termination();
             instance->state = InfraredWorkerStateStartTx;
 
-            events = osThreadFlagsGet();
+            events = furi_thread_flags_get();
             if(events & INFRARED_WORKER_EXIT) {
                 exit = true;
                 break;
@@ -506,7 +506,7 @@ static int32_t infrared_worker_tx_thread(void* thread_context) {
 
             break;
         case InfraredWorkerStateRunTx:
-            events = osThreadFlagsWait(INFRARED_WORKER_ALL_TX_EVENTS, 0, osWaitForever);
+            events = furi_thread_flags_wait(INFRARED_WORKER_ALL_TX_EVENTS, 0, osWaitForever);
             furi_check(events & INFRARED_WORKER_ALL_TX_EVENTS); /* at least one caught */
 
             if(events & INFRARED_WORKER_EXIT) {
@@ -558,7 +558,7 @@ void infrared_worker_tx_stop(InfraredWorker* instance) {
     furi_assert(instance);
     furi_assert(instance->state != InfraredWorkerStateRunRx);
 
-    osThreadFlagsSet(furi_thread_get_thread_id(instance->thread), INFRARED_WORKER_EXIT);
+    furi_thread_flags_set(furi_thread_get_id(instance->thread), INFRARED_WORKER_EXIT);
     furi_thread_join(instance->thread);
     furi_hal_infrared_async_tx_set_data_isr_callback(NULL, NULL);
     furi_hal_infrared_async_tx_set_signal_sent_isr_callback(NULL, NULL);

+ 3 - 2
lib/subghz/subghz_file_encoder_worker.c

@@ -216,8 +216,9 @@ bool subghz_file_encoder_worker_start(SubGhzFileEncoderWorker* instance, const c
     xStreamBufferReset(instance->stream);
     string_set(instance->file_path, file_path);
     instance->worker_running = true;
-    bool res = furi_thread_start(instance->thread);
-    return res;
+    furi_thread_start(instance->thread);
+
+    return true;
 }
 
 void subghz_file_encoder_worker_stop(SubGhzFileEncoderWorker* instance) {

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels