From 839e52ac32ada5eaa08796a2022c7aa6187845a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Mon, 20 Jun 2022 17:54:48 +0300 Subject: [PATCH] [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 --- applications/bad_usb/bad_usb_script.c | 18 +- applications/cli/cli_commands.c | 12 +- applications/cli/cli_vcp.c | 19 +- applications/debug_tools/uart_echo.c | 7 +- applications/gpio/usb_uart_bridge.c | 26 +- applications/gui/gui.c | 11 +- applications/gui/gui_i.h | 2 +- .../gui/modules/file_browser_worker.c | 18 +- applications/input/input.c | 6 +- applications/input/input_i.h | 2 +- applications/loader/loader.c | 15 +- applications/loader/loader_i.h | 2 +- applications/rpc/rpc.c | 8 +- applications/rpc/rpc_gui.c | 12 +- applications/subghz/helpers/subghz_chat.c | 4 +- applications/u2f/u2f_hid.c | 12 +- .../unit_tests/furi_valuemutex_test.c | 88 - applications/unit_tests/minunit_test.c | 5 - .../unit_tests/storage/storage_test.c | 4 +- applications/unit_tests/subghz/subghz_test.c | 4 +- applications/updater/util/update_task.c | 4 +- applications/updater/util/update_task.h | 2 +- core/furi.h | 7 +- core/furi/base.h | 45 + core/furi/check.c | 5 +- core/furi/check.h | 1 + core/furi/event_flags.c | 222 +++ core/furi/event_flags.h | 63 + core/furi/log.c | 1 + core/furi/memmgr_heap.c | 14 +- core/furi/memmgr_heap.h | 8 +- core/furi/mutex.c | 217 ++ core/furi/mutex.h | 56 + core/furi/pubsub.c | 2 +- core/furi/record.c | 3 +- core/furi/semaphore.c | 190 ++ core/furi/semaphore.h | 57 + core/furi/stdglue.c | 14 +- core/furi/thread.c | 293 ++- core/furi/thread.h | 77 +- core/furi/valuemutex.h | 1 + firmware/targets/f7/Inc/FreeRTOSConfig.h | 7 +- firmware/targets/f7/Src/main.c | 18 +- firmware/targets/f7/ble_glue/ble_app.c | 11 +- firmware/targets/f7/ble_glue/ble_glue.c | 10 +- firmware/targets/f7/furi_hal/furi_hal_bt.c | 2 +- firmware/targets/f7/furi_hal/furi_hal_crc.c | 2 +- firmware/targets/f7/furi_hal/furi_hal_flash.c | 12 +- firmware/targets/f7/furi_hal/furi_hal_nfc.c | 6 +- .../targets/f7/furi_hal/furi_hal_resources.c | 4 +- .../targets/f7/furi_hal/furi_hal_resources.h | 2 +- firmware/targets/f7/furi_hal/furi_hal_rfid.c | 18 +- firmware/targets/f7/furi_hal/furi_hal_usb.c | 16 +- lib/FreeRTOS-glue/cmsis_os2.c | 1756 +---------------- lib/FreeRTOS-glue/cmsis_os2.h | 572 +----- lib/FreeRTOS-glue/freertos_mpool.h | 63 - lib/FreeRTOS-glue/freertos_os2.h | 31 +- lib/FreeRTOS-glue/os_tick.h | 80 - lib/ST25RFAL002/platform.c | 51 +- lib/infrared/worker/infrared_worker.c | 28 +- lib/subghz/subghz_file_encoder_worker.c | 5 +- 61 files changed, 1467 insertions(+), 2784 deletions(-) create mode 100644 core/furi/base.h create mode 100644 core/furi/event_flags.c create mode 100644 core/furi/event_flags.h create mode 100644 core/furi/mutex.c create mode 100644 core/furi/mutex.h create mode 100644 core/furi/semaphore.c create mode 100644 core/furi/semaphore.h delete mode 100644 lib/FreeRTOS-glue/freertos_mpool.h delete mode 100644 lib/FreeRTOS-glue/os_tick.h diff --git a/applications/bad_usb/bad_usb_script.c b/applications/bad_usb/bad_usb_script.c index 685e5083..0266b51f 100644 --- a/applications/bad_usb/bad_usb_script.c +++ b/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) { diff --git a/applications/cli/cli_commands.c b/applications/cli/cli_commands.c index 8271ab31..c99f4edc 100644 --- a/applications/cli/cli_commands.c +++ b/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); } diff --git a/applications/cli/cli_vcp.c b/applications/cli/cli_vcp.c index 84edca18..7e23e4b1 100644 --- a/applications/cli/cli_vcp.c +++ b/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) { diff --git a/applications/debug_tools/uart_echo.c b/applications/debug_tools/uart_echo.c index 206c6c06..213769a5 100644 --- a/applications/debug_tools/uart_echo.c +++ b/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); diff --git a/applications/gpio/usb_uart_bridge.c b/applications/gpio/usb_uart_bridge.c index f70cf640..cf7e7687 100644 --- a/applications/gpio/usb_uart_bridge.c +++ b/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) { diff --git a/applications/gui/gui.c b/applications/gui/gui.c index 77ee4487..d9e32cdd 100644 --- a/applications/gui/gui.c +++ b/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); } } diff --git a/applications/gui/gui_i.h b/applications/gui/gui_i.h index ea26339d..abe85615 100644 --- a/applications/gui/gui_i.h +++ b/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 diff --git a/applications/gui/modules/file_browser_worker.c b/applications/gui/modules/file_browser_worker.c index 4931cb26..cd7b6cb7 100644 --- a/applications/gui/modules/file_browser_worker.c +++ b/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); } diff --git a/applications/input/input.c b/applications/input/input.c index dd824dcb..2be67a71 100644 --- a/applications/input/input.c +++ b/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); } } diff --git a/applications/input/input_i.h b/applications/input/input_i.h index 4bd777ef..63a9c85a 100644 --- a/applications/input/input_i.h +++ b/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; diff --git a/applications/loader/loader.c b/applications/loader/loader.c index e5d59702..1acff8b7 100644 --- a/applications/loader/loader.c +++ b/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( diff --git a/applications/loader/loader_i.h b/applications/loader/loader_i.h index 4c937b94..a311c6e8 100644 --- a/applications/loader/loader_i.h +++ b/applications/loader/loader_i.h @@ -15,7 +15,7 @@ #include struct Loader { - osThreadId_t loader_thread; + FuriThreadId loader_thread; const FlipperApplication* application; FuriThread* application_thread; diff --git a/applications/rpc/rpc.c b/applications/rpc/rpc.c index 7d51defd..c974a0e5 100644 --- a/applications/rpc/rpc.c +++ b/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) { diff --git a/applications/rpc/rpc_gui.c b/applications/rpc/rpc_gui.c index f390d983..da91ae06 100644 --- a/applications/rpc/rpc_gui.c +++ b/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 diff --git a/applications/subghz/helpers/subghz_chat.c b/applications/subghz/helpers/subghz_chat.c index e6b7b7bc..7a359165 100644 --- a/applications/subghz/helpers/subghz_chat.c +++ b/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; } diff --git a/applications/u2f/u2f_hid.c b/applications/u2f/u2f_hid.c index a2b291d6..581feadb 100644 --- a/applications/u2f/u2f_hid.c +++ b/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); diff --git a/applications/unit_tests/furi_valuemutex_test.c b/applications/unit_tests/furi_valuemutex_test.c index 4deb4f61..12613239 100644 --- a/applications/unit_tests/furi_valuemutex_test.c +++ b/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)); - */ -} diff --git a/applications/unit_tests/minunit_test.c b/applications/unit_tests/minunit_test.c index 1e71fd07..9d564df6 100644 --- a/applications/unit_tests/minunit_test.c +++ b/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); } diff --git a/applications/unit_tests/storage/storage_test.c b/applications/unit_tests/storage/storage_test.c index 9f237bd0..db78583d 100644 --- a/applications/unit_tests/storage/storage_test.c +++ b/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); diff --git a/applications/unit_tests/subghz/subghz_test.c b/applications/unit_tests/subghz/subghz_test.c index c8f23780..680f199a 100644 --- a/applications/unit_tests/subghz/subghz_test.c +++ b/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; diff --git a/applications/updater/util/update_task.c b/applications/updater/util/update_task.c index fd2344c1..58b0c975 100644 --- a/applications/updater/util/update_task.c +++ b/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) { diff --git a/applications/updater/util/update_task.h b/applications/updater/util/update_task.h index cfbbb850..ac9dadd6 100644 --- a/applications/updater/util/update_task.h +++ b/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); diff --git a/core/furi.h b/core/furi.h index 6a0d1b0a..7a36c1ba 100644 --- a/core/furi.h +++ b/core/furi.h @@ -6,16 +6,19 @@ #include -#include #include +#include +#include +#include #include #include +#include #include #include +#include #include #include #include -#include #include diff --git a/core/furi/base.h b/core/furi/base.h new file mode 100644 index 00000000..41873fbd --- /dev/null +++ b/core/furi/base.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include + +// FreeRTOS part +#include + +#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 diff --git a/core/furi/check.c b/core/furi/check.c index b59e490c..ca945ada 100644 --- a/core/furi/check.c +++ b/core/furi/check.c @@ -6,11 +6,14 @@ #include #include +#include +#include + 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 { diff --git a/core/furi/check.h b/core/furi/check.h index 4165c3c2..30efdf01 100644 --- a/core/furi/check.h +++ b/core/furi/check.h @@ -1,4 +1,5 @@ #pragma once + #ifdef __cplusplus extern "C" { #define FURI_NORETURN [[noreturn]] diff --git a/core/furi/event_flags.c b/core/furi/event_flags.c new file mode 100644 index 00000000..ba8cba48 --- /dev/null +++ b/core/furi/event_flags.c @@ -0,0 +1,222 @@ +#include "event_flags.h" +#include "common_defines.h" + +#include + +#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); +} diff --git a/core/furi/event_flags.h b/core/furi/event_flags.h new file mode 100644 index 00000000..66aa2d7a --- /dev/null +++ b/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 diff --git a/core/furi/log.c b/core/furi/log.c index 9ce025b9..4653603c 100644 --- a/core/furi/log.c +++ b/core/furi/log.c @@ -1,5 +1,6 @@ #include "log.h" #include "check.h" +#include "mutex.h" #include #include diff --git a/core/furi/memmgr_heap.c b/core/furi/memmgr_heap.c index 618d7e74..92e99b92 100644 --- a/core/furi/memmgr_heap.c +++ b/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 = ""; } diff --git a/core/furi/memmgr_heap.h b/core/furi/memmgr_heap.h index 04dced06..f76102ec 100644 --- a/core/furi/memmgr_heap.h +++ b/core/furi/memmgr_heap.h @@ -6,7 +6,7 @@ #pragma once #include -#include +#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 * diff --git a/core/furi/mutex.c b/core/furi/mutex.c new file mode 100644 index 00000000..42f1d528 --- /dev/null +++ b/core/furi/mutex.c @@ -0,0 +1,217 @@ +#include "mutex.h" +#include "check.h" +#include "common_defines.h" + +#include + +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); +} diff --git a/core/furi/mutex.h b/core/furi/mutex.h new file mode 100644 index 00000000..44f351b7 --- /dev/null +++ b/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 diff --git a/core/furi/pubsub.c b/core/furi/pubsub.c index 8e9adda8..88839ec2 100644 --- a/core/furi/pubsub.c +++ b/core/furi/pubsub.c @@ -1,9 +1,9 @@ #include "pubsub.h" #include "memmgr.h" #include "check.h" +#include "mutex.h" #include -#include struct FuriPubSubSubscription { FuriPubSubCallback callback; diff --git a/core/furi/record.c b/core/furi/record.c index 501091d4..d7afbf9c 100644 --- a/core/furi/record.c +++ b/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 #include #include diff --git a/core/furi/semaphore.c b/core/furi/semaphore.c new file mode 100644 index 00000000..cbacdef0 --- /dev/null +++ b/core/furi/semaphore.c @@ -0,0 +1,190 @@ +#include "semaphore.h" +#include "check.h" +#include "common_defines.h" + +#include + +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); +} diff --git a/core/furi/semaphore.h b/core/furi/semaphore.h new file mode 100644 index 00000000..b4de78fd --- /dev/null +++ b/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 diff --git a/core/furi/stdglue.c b/core/furi/stdglue.c index 1eccafc9..8c1d0813 100644 --- a/core/furi/stdglue.c +++ b/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; diff --git a/core/furi/thread.c b/core/furi/thread.c index a2898c1a..692e5e05 100644 --- a/core/furi/thread.c +++ b/core/furi/thread.c @@ -2,7 +2,9 @@ #include "memmgr.h" #include "memmgr_heap.h" #include "check.h" +#include "common_defines.h" +#include #include 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; - } + + 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_terminate(FuriThread* thread) { +bool furi_thread_join(FuriThread* thread) { furi_assert(thread); - osStatus_t ret = osThreadTerminate(thread->id); - if(ret == osOK) { - furi_thread_set_state(thread, FuriThreadStateStopped); - } - return ret; -} -osStatus_t 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); +} diff --git a/core/furi/thread.h b/core/furi/thread.h index 83e6bb93..11dd997c 100644 --- a/core/furi/thread.h +++ b/core/furi/thread.h @@ -5,9 +5,7 @@ #pragma once -#include -#include -#include +#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 diff --git a/core/furi/valuemutex.h b/core/furi/valuemutex.h index 63dfac61..bd149316 100644 --- a/core/furi/valuemutex.h +++ b/core/furi/valuemutex.h @@ -2,6 +2,7 @@ #include #include +#include "mutex.h" #ifdef __cplusplus extern "C" { diff --git a/firmware/targets/f7/Inc/FreeRTOSConfig.h b/firmware/targets/f7/Inc/FreeRTOSConfig.h index 0204826a..9f1b83c0 100644 --- a/firmware/targets/f7/Inc/FreeRTOSConfig.h +++ b/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 diff --git a/firmware/targets/f7/Src/main.c b/firmware/targets/f7/Src/main.c index 3de1c6ca..82a2819b 100644 --- a/firmware/targets/f7/Src/main.c +++ b/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 diff --git a/firmware/targets/f7/ble_glue/ble_app.c b/firmware/targets/f7/ble_glue/ble_app.c index 618e2b94..f0406a88 100644 --- a/firmware/targets/f7/ble_glue/ble_app.c +++ b/firmware/targets/f7/ble_glue/ble_app.c @@ -6,6 +6,7 @@ #include "gap.h" #include +#include #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); } } diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/firmware/targets/f7/ble_glue/ble_glue.c index 6a100bea..dd3fc280 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.c +++ b/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); } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/firmware/targets/f7/furi_hal/furi_hal_bt.c index c7ee7dc2..ad12d773 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt.c +++ b/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(); } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_crc.c b/firmware/targets/f7/furi_hal/furi_hal_crc.c index 322a83bb..9ac13e97 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_crc.c +++ b/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); diff --git a/firmware/targets/f7/furi_hal/furi_hal_flash.c b/firmware/targets/f7/furi_hal/furi_hal_flash.c index 1d9c3fd9..ac141db0 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_flash.c +++ b/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 */ diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 6ffb6e3a..3e6d18eb 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/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; diff --git a/firmware/targets/f7/furi_hal/furi_hal_resources.c b/firmware/targets/f7/furi_hal/furi_hal_resources.c index 0af33cac..21fac834 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_resources.c +++ b/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); diff --git a/firmware/targets/f7/furi_hal/furi_hal_resources.h b/firmware/targets/f7/furi_hal/furi_hal_resources.h index e9d19827..820760a1 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_resources.h +++ b/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; diff --git a/firmware/targets/f7/furi_hal/furi_hal_rfid.c b/firmware/targets/f7/furi_hal/furi_hal_rfid.c index 86fecc99..507c53bf 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rfid.c +++ b/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) { diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb.c b/firmware/targets/f7/furi_hal/furi_hal_usb.c index 6a5e534e..cedcc82a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb.c +++ b/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) { diff --git a/lib/FreeRTOS-glue/cmsis_os2.c b/lib/FreeRTOS-glue/cmsis_os2.c index 4e59fb54..bee37572 100644 --- a/lib/FreeRTOS-glue/cmsis_os2.c +++ b/lib/FreeRTOS-glue/cmsis_os2.c @@ -26,15 +26,11 @@ #include "cmsis_os2.h" // ::CMSIS:RTOS2 #include "cmsis_compiler.h" // Compiler agnostic definitions -#include "os_tick.h" // OS Tick API #include "FreeRTOS.h" // ARM.FreeRTOS::RTOS:Core -#include "task.h" // ARM.FreeRTOS::RTOS:Core -#include "event_groups.h" // ARM.FreeRTOS::RTOS:Event Groups -#include "semphr.h" // ARM.FreeRTOS::RTOS:Core #include "timers.h" // ARM.FreeRTOS::RTOS:Timers +#include "queue.h" -#include "freertos_mpool.h" // osMemoryPool definitions #include "freertos_os2.h" // Configuration check and setup #include CMSIS_device_header @@ -87,10 +83,8 @@ /* Limits */ #define MAX_BITS_TASK_NOTIFY 31U -#define MAX_BITS_EVENT_GROUPS 24U #define THREAD_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_TASK_NOTIFY) - 1U)) -#define EVENT_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_EVENT_GROUPS) - 1U)) /* Kernel version and identification string definition (major.minor.rev: mmnnnrrrr dec) */ #define KERNEL_VERSION (((uint32_t)tskKERNEL_VERSION_MAJOR * 10000000UL) | \ @@ -453,31 +447,6 @@ uint32_t osKernelGetTickFreq (void) { return (configTICK_RATE_HZ); } -/* - Get the RTOS kernel system timer count. -*/ -uint32_t osKernelGetSysTimerCount (void) { - TickType_t ticks; - uint32_t val; - - FURI_CRITICAL_ENTER(); - - ticks = xTaskGetTickCount(); - val = OS_Tick_GetCount(); - - /* Update tick count and timer value when timer overflows */ - if (OS_Tick_GetOverflow() != 0U) { - val = OS_Tick_GetCount(); - ticks++; - } - val += ticks * OS_Tick_GetInterval(); - - FURI_CRITICAL_EXIT(); - - /* Return system timer count */ - return (val); -} - /* Get the RTOS kernel system timer frequency. */ @@ -486,531 +455,6 @@ uint32_t osKernelGetSysTimerFreq (void) { return (configCPU_CLOCK_HZ); } - -/* ==== Thread Management Functions ==== */ - -/* - Create a thread and add it to Active Threads. - - Limitations: - - The memory for control block and stack must be provided in the osThreadAttr_t - structure in order to allocate object statically. - - Attribute osThreadJoinable is not supported, NULL is returned if used. -*/ -osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr) { - const char *name; - uint32_t stack; - TaskHandle_t hTask; - UBaseType_t prio; - int32_t mem; - - hTask = NULL; - - if ((IRQ_Context() == 0U) && (func != NULL)) { - stack = configMINIMAL_STACK_SIZE; - prio = (UBaseType_t)osPriorityNormal; - - name = NULL; - mem = -1; - - if (attr != NULL) { - if (attr->name != NULL) { - name = attr->name; - } - if (attr->priority != osPriorityNone) { - prio = (UBaseType_t)attr->priority; - } - - if ((prio < osPriorityIdle) || (prio > osPriorityISR) || ((attr->attr_bits & osThreadJoinable) == osThreadJoinable)) { - /* Invalid priority or unsupported osThreadJoinable attribute used */ - return (NULL); - } - - if (attr->stack_size > 0U) { - /* In FreeRTOS stack is not in bytes, but in sizeof(StackType_t) which is 4 on ARM ports. */ - /* Stack size should be therefore 4 byte aligned in order to avoid division caused side effects */ - stack = attr->stack_size / sizeof(StackType_t); - } - - if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticTask_t)) && - (attr->stack_mem != NULL) && (attr->stack_size > 0U)) { - /* The memory for control block and stack is provided, use static object */ - mem = 1; - } - else { - if ((attr->cb_mem == NULL) && (attr->cb_size == 0U) && (attr->stack_mem == NULL)) { - /* Control block and stack memory will be allocated from the dynamic pool */ - mem = 0; - } - } - } - else { - mem = 0; - } - - if (mem == 1) { - #if (configSUPPORT_STATIC_ALLOCATION == 1) - hTask = xTaskCreateStatic ((TaskFunction_t)func, name, stack, argument, prio, (StackType_t *)attr->stack_mem, - (StaticTask_t *)attr->cb_mem); - #endif - } - else { - if (mem == 0) { - #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) - if (xTaskCreate ((TaskFunction_t)func, name, (configSTACK_DEPTH_TYPE)stack, argument, prio, &hTask) != pdPASS) { - hTask = NULL; - } - #endif - } - } - } - - /* Return thread ID */ - return ((osThreadId_t)hTask); -} - -/* - Get name of a thread. -*/ -const char *osThreadGetName (osThreadId_t thread_id) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - const char *name; - - if ((IRQ_Context() != 0U) || (hTask == NULL)) { - name = NULL; - } else if(osKernelGetState() == osKernelRunning) { - name = pcTaskGetName (hTask); - } else { - name = NULL; - } - - /* Return name as null-terminated string */ - return (name); -} - -/* - Return the thread ID of the current running thread. -*/ -osThreadId_t osThreadGetId (void) { - osThreadId_t id; - - id = (osThreadId_t)xTaskGetCurrentTaskHandle(); - - /* Return thread ID */ - return (id); -} - -/* - Get current thread state of a thread. -*/ -osThreadState_t osThreadGetState (osThreadId_t thread_id) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - osThreadState_t state; - - if ((IRQ_Context() != 0U) || (hTask == NULL)) { - state = osThreadError; - } - else { - switch (eTaskGetState (hTask)) { - case eRunning: state = osThreadRunning; break; - case eReady: state = osThreadReady; break; - case eBlocked: - case eSuspended: state = osThreadBlocked; break; - case eDeleted: state = osThreadTerminated; break; - case eInvalid: - default: state = osThreadError; break; - } - } - - /* Return current thread state */ - return (state); -} - -/* - Get available stack space of a thread based on stack watermark recording during execution. -*/ -uint32_t osThreadGetStackSpace (osThreadId_t thread_id) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - uint32_t sz; - - if ((IRQ_Context() != 0U) || (hTask == NULL)) { - sz = 0U; - } else { - sz = (uint32_t)(uxTaskGetStackHighWaterMark(hTask) * sizeof(StackType_t)); - } - - /* Return remaining stack space in bytes */ - return (sz); -} - -/* - Change priority of a thread. -*/ -osStatus_t osThreadSetPriority (osThreadId_t thread_id, osPriority_t priority) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - osStatus_t stat; - - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if ((hTask == NULL) || (priority < osPriorityIdle) || (priority > osPriorityISR)) { - stat = osErrorParameter; - } - else { - stat = osOK; - vTaskPrioritySet (hTask, (UBaseType_t)priority); - } - - /* Return execution status */ - return (stat); -} - -/* - Get current priority of a thread. -*/ -osPriority_t osThreadGetPriority (osThreadId_t thread_id) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - osPriority_t prio; - - if ((IRQ_Context() != 0U) || (hTask == NULL)) { - prio = osPriorityError; - } else { - prio = (osPriority_t)((int32_t)uxTaskPriorityGet (hTask)); - } - - /* Return current thread priority */ - return (prio); -} - -/* - Pass control to next thread that is in state READY. -*/ -osStatus_t osThreadYield (void) { - osStatus_t stat; - - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } else { - stat = osOK; - taskYIELD(); - } - - /* Return execution status */ - return (stat); -} - -#if (configUSE_OS2_THREAD_SUSPEND_RESUME == 1) -/* - Suspend execution of a thread. -*/ -osStatus_t osThreadSuspend (osThreadId_t thread_id) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - osStatus_t stat; - - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if (hTask == NULL) { - stat = osErrorParameter; - } - else { - stat = osOK; - vTaskSuspend (hTask); - } - - /* Return execution status */ - return (stat); -} - -/* - Resume execution of a thread. -*/ -osStatus_t osThreadResume (osThreadId_t thread_id) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - osStatus_t stat; - - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if (hTask == NULL) { - stat = osErrorParameter; - } - else { - stat = osOK; - vTaskResume (hTask); - } - - /* Return execution status */ - return (stat); -} -#endif /* (configUSE_OS2_THREAD_SUSPEND_RESUME == 1) */ - -/* - Terminate execution of current running thread. -*/ -__NO_RETURN void osThreadExit (void) { -#ifndef USE_FreeRTOS_HEAP_1 - vTaskDelete (NULL); -#endif - for (;;); -} - -/* - Terminate execution of a thread. -*/ -osStatus_t osThreadTerminate (osThreadId_t thread_id) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - osStatus_t stat; -#ifndef USE_FreeRTOS_HEAP_1 - eTaskState tstate; - - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if (hTask == NULL) { - stat = osErrorParameter; - } - else { - tstate = eTaskGetState (hTask); - - if (tstate != eDeleted) { - stat = osOK; - vTaskDelete (hTask); - } else { - stat = osErrorResource; - } - } -#else - stat = osError; -#endif - - /* Return execution status */ - return (stat); -} - -/* - Get number of active threads. -*/ -uint32_t osThreadGetCount (void) { - uint32_t count; - - if (IRQ_Context() != 0U) { - count = 0U; - } else { - count = uxTaskGetNumberOfTasks(); - } - - /* Return number of active threads */ - return (count); -} - -#if (configUSE_OS2_THREAD_ENUMERATE == 1) -/* - Enumerate active threads. -*/ -uint32_t osThreadEnumerate (osThreadId_t *thread_array, uint32_t array_items) { - uint32_t i, count; - TaskStatus_t *task; - - if ((IRQ_Context() != 0U) || (thread_array == NULL) || (array_items == 0U)) { - count = 0U; - } else { - vTaskSuspendAll(); - - /* Allocate memory on heap to temporarily store TaskStatus_t information */ - count = uxTaskGetNumberOfTasks(); - task = pvPortMalloc (count * sizeof(TaskStatus_t)); - - if (task != NULL) { - /* Retrieve task status information */ - count = uxTaskGetSystemState (task, count, NULL); - - /* Copy handles from task status array into provided thread array */ - for (i = 0U; (i < count) && (i < array_items); i++) { - thread_array[i] = (osThreadId_t)task[i].xHandle; - } - count = i; - } - (void)xTaskResumeAll(); - - vPortFree (task); - } - - /* Return number of enumerated threads */ - return (count); -} -#endif /* (configUSE_OS2_THREAD_ENUMERATE == 1) */ - - -/* ==== Thread Flags Functions ==== */ - -#if (configUSE_OS2_THREAD_FLAGS == 1) -/* - Set the specified Thread Flags of a thread. -*/ -uint32_t osThreadFlagsSet (osThreadId_t thread_id, uint32_t flags) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - uint32_t rflags; - BaseType_t yield; - - if ((hTask == NULL) || ((flags & THREAD_FLAGS_INVALID_BITS) != 0U)) { - rflags = (uint32_t)osErrorParameter; - } - else { - rflags = (uint32_t)osError; - - if (IRQ_Context() != 0U) { - yield = pdFALSE; - - (void)xTaskNotifyIndexedFromISR (hTask, CMSIS_TASK_NOTIFY_INDEX, flags, eSetBits, &yield); - (void)xTaskNotifyAndQueryIndexedFromISR (hTask, CMSIS_TASK_NOTIFY_INDEX, 0, eNoAction, &rflags, NULL); - - portYIELD_FROM_ISR (yield); - } - else { - (void)xTaskNotifyIndexed (hTask, CMSIS_TASK_NOTIFY_INDEX, flags, eSetBits); - (void)xTaskNotifyAndQueryIndexed (hTask, CMSIS_TASK_NOTIFY_INDEX, 0, eNoAction, &rflags); - } - } - /* Return flags after setting */ - return (rflags); -} - -/* - Clear the specified Thread Flags of current running thread. -*/ -uint32_t osThreadFlagsClear (uint32_t flags) { - TaskHandle_t hTask; - uint32_t rflags, cflags; - - if (IRQ_Context() != 0U) { - rflags = (uint32_t)osErrorISR; - } - else if ((flags & THREAD_FLAGS_INVALID_BITS) != 0U) { - rflags = (uint32_t)osErrorParameter; - } - else { - hTask = xTaskGetCurrentTaskHandle(); - - if (xTaskNotifyAndQueryIndexed (hTask, CMSIS_TASK_NOTIFY_INDEX, 0, eNoAction, &cflags) == pdPASS) { - rflags = cflags; - cflags &= ~flags; - - if (xTaskNotifyIndexed (hTask, CMSIS_TASK_NOTIFY_INDEX, cflags, eSetValueWithOverwrite) != pdPASS) { - rflags = (uint32_t)osError; - } - } - else { - rflags = (uint32_t)osError; - } - } - - /* Return flags before clearing */ - return (rflags); -} - -/* - Get the current Thread Flags of current running thread. -*/ -uint32_t osThreadFlagsGet (void) { - TaskHandle_t hTask; - uint32_t rflags; - - if (IRQ_Context() != 0U) { - rflags = (uint32_t)osErrorISR; - } - else { - hTask = xTaskGetCurrentTaskHandle(); - - if (xTaskNotifyAndQueryIndexed (hTask, CMSIS_TASK_NOTIFY_INDEX, 0, eNoAction, &rflags) != pdPASS) { - rflags = (uint32_t)osError; - } - } - - /* Return current flags */ - return (rflags); -} - -/* - Wait for one or more Thread Flags of the current running thread to become signaled. -*/ -uint32_t osThreadFlagsWait (uint32_t flags, uint32_t options, uint32_t timeout) { - uint32_t rflags, nval; - uint32_t clear; - TickType_t t0, td, tout; - BaseType_t rval; - - if (IRQ_Context() != 0U) { - rflags = (uint32_t)osErrorISR; - } - else if ((flags & THREAD_FLAGS_INVALID_BITS) != 0U) { - rflags = (uint32_t)osErrorParameter; - } - else { - if ((options & osFlagsNoClear) == osFlagsNoClear) { - clear = 0U; - } else { - clear = flags; - } - - rflags = 0U; - tout = timeout; - - t0 = xTaskGetTickCount(); - do { - rval = xTaskNotifyWaitIndexed (CMSIS_TASK_NOTIFY_INDEX, 0, clear, &nval, tout); - - if (rval == pdPASS) { - rflags &= flags; - rflags |= nval; - - if ((options & osFlagsWaitAll) == osFlagsWaitAll) { - if ((flags & rflags) == flags) { - break; - } else { - if (timeout == 0U) { - rflags = (uint32_t)osErrorResource; - break; - } - } - } - else { - if ((flags & rflags) != 0) { - break; - } else { - if (timeout == 0U) { - rflags = (uint32_t)osErrorResource; - break; - } - } - } - - /* Update timeout */ - td = xTaskGetTickCount() - t0; - - if (td > timeout) { - tout = 0; - } else { - tout = timeout - td; - } - } - else { - if (timeout == 0) { - rflags = (uint32_t)osErrorResource; - } else { - rflags = (uint32_t)osErrorTimeout; - } - } - } - while (rval != pdFAIL); - } - - /* Return flags before clearing */ - return (rflags); -} -#endif /* (configUSE_OS2_THREAD_FLAGS == 1) */ - - /* ==== Generic Wait Functions ==== */ /* @@ -1330,681 +774,6 @@ osStatus_t osTimerDelete (osTimerId_t timer_id) { #endif /* (configUSE_OS2_TIMER == 1) */ -/* ==== Event Flags Management Functions ==== */ - -/* - Create and Initialize an Event Flags object. - - Limitations: - - Event flags are limited to 24 bits. -*/ -osEventFlagsId_t osEventFlagsNew (const osEventFlagsAttr_t *attr) { - EventGroupHandle_t hEventGroup; - int32_t mem; - - hEventGroup = NULL; - - if (IRQ_Context() == 0U) { - mem = -1; - - if (attr != NULL) { - if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticEventGroup_t))) { - /* The memory for control block is provided, use static object */ - mem = 1; - } - else { - if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) { - /* Control block will be allocated from the dynamic pool */ - mem = 0; - } - } - } - else { - mem = 0; - } - - if (mem == 1) { - #if (configSUPPORT_STATIC_ALLOCATION == 1) - hEventGroup = xEventGroupCreateStatic (attr->cb_mem); - #endif - } - else { - if (mem == 0) { - #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) - hEventGroup = xEventGroupCreate(); - #endif - } - } - } - - /* Return event flags ID */ - return ((osEventFlagsId_t)hEventGroup); -} - -/* - Set the specified Event Flags. - - Limitations: - - Event flags are limited to 24 bits. -*/ -uint32_t osEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags) { - EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; - uint32_t rflags; - BaseType_t yield; - - if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) { - rflags = (uint32_t)osErrorParameter; - } - else if (IRQ_Context() != 0U) { - #if (configUSE_OS2_EVENTFLAGS_FROM_ISR == 0) - (void)yield; - /* Enable timers and xTimerPendFunctionCall function to support osEventFlagsSet from ISR */ - rflags = (uint32_t)osErrorResource; - #else - yield = pdFALSE; - - if (xEventGroupSetBitsFromISR (hEventGroup, (EventBits_t)flags, &yield) == pdFAIL) { - rflags = (uint32_t)osErrorResource; - } else { - rflags = flags; - portYIELD_FROM_ISR (yield); - } - #endif - } - else { - rflags = xEventGroupSetBits (hEventGroup, (EventBits_t)flags); - } - - /* Return event flags after setting */ - return (rflags); -} - -/* - Clear the specified Event Flags. - - Limitations: - - Event flags are limited to 24 bits. -*/ -uint32_t osEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags) { - EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; - uint32_t rflags; - - if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) { - rflags = (uint32_t)osErrorParameter; - } - else if (IRQ_Context() != 0U) { - #if (configUSE_OS2_EVENTFLAGS_FROM_ISR == 0) - /* Enable timers and xTimerPendFunctionCall function to support osEventFlagsSet from ISR */ - rflags = (uint32_t)osErrorResource; - #else - rflags = xEventGroupGetBitsFromISR (hEventGroup); - - if (xEventGroupClearBitsFromISR (hEventGroup, (EventBits_t)flags) == pdFAIL) { - rflags = (uint32_t)osErrorResource; - } - else { - /* xEventGroupClearBitsFromISR only registers clear operation in the timer command queue. */ - /* Yield is required here otherwise clear operation might not execute in the right order. */ - /* See https://github.com/FreeRTOS/FreeRTOS-Kernel/issues/93 for more info. */ - portYIELD_FROM_ISR (pdTRUE); - } - #endif - } - else { - rflags = xEventGroupClearBits (hEventGroup, (EventBits_t)flags); - } - - /* Return event flags before clearing */ - return (rflags); -} - -/* - Get the current Event Flags. - - Limitations: - - Event flags are limited to 24 bits. -*/ -uint32_t osEventFlagsGet (osEventFlagsId_t ef_id) { - EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; - uint32_t rflags; - - if (ef_id == NULL) { - rflags = 0U; - } - else if (IRQ_Context() != 0U) { - rflags = xEventGroupGetBitsFromISR (hEventGroup); - } - else { - rflags = xEventGroupGetBits (hEventGroup); - } - - /* Return current event flags */ - return (rflags); -} - -/* - Wait for one or more Event Flags to become signaled. - - Limitations: - - Event flags are limited to 24 bits. - - osEventFlagsWait cannot be called from an ISR. -*/ -uint32_t osEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout) { - EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; - BaseType_t wait_all; - BaseType_t exit_clr; - uint32_t rflags; - - if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) { - rflags = (uint32_t)osErrorParameter; - } - else if (IRQ_Context() != 0U) { - rflags = (uint32_t)osErrorISR; - } - else { - if (options & osFlagsWaitAll) { - wait_all = pdTRUE; - } else { - wait_all = pdFAIL; - } - - if (options & osFlagsNoClear) { - exit_clr = pdFAIL; - } else { - exit_clr = pdTRUE; - } - - rflags = xEventGroupWaitBits (hEventGroup, (EventBits_t)flags, exit_clr, wait_all, (TickType_t)timeout); - - if (options & osFlagsWaitAll) { - if ((flags & rflags) != flags) { - if (timeout > 0U) { - rflags = (uint32_t)osErrorTimeout; - } else { - rflags = (uint32_t)osErrorResource; - } - } - } - else { - if ((flags & rflags) == 0U) { - if (timeout > 0U) { - rflags = (uint32_t)osErrorTimeout; - } else { - rflags = (uint32_t)osErrorResource; - } - } - } - } - - /* Return event flags before clearing */ - return (rflags); -} - -/* - Delete an Event Flags object. -*/ -osStatus_t osEventFlagsDelete (osEventFlagsId_t ef_id) { - EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; - osStatus_t stat; - -#ifndef USE_FreeRTOS_HEAP_1 - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if (hEventGroup == NULL) { - stat = osErrorParameter; - } - else { - stat = osOK; - vEventGroupDelete (hEventGroup); - } -#else - stat = osError; -#endif - - /* Return execution status */ - return (stat); -} - - -/* ==== Mutex Management Functions ==== */ - -#if (configUSE_OS2_MUTEX == 1) -/* - Create and Initialize a Mutex object. - - Limitations: - - Priority inherit protocol is used by default, osMutexPrioInherit attribute is ignored. - - Robust mutex is not supported, NULL is returned if used. -*/ -osMutexId_t osMutexNew (const osMutexAttr_t *attr) { - SemaphoreHandle_t hMutex; - uint32_t type; - uint32_t rmtx; - int32_t mem; - - hMutex = NULL; - - if (IRQ_Context() == 0U) { - if (attr != NULL) { - type = attr->attr_bits; - } else { - type = 0U; - } - - if ((type & osMutexRecursive) == osMutexRecursive) { - rmtx = 1U; - } else { - rmtx = 0U; - } - - if ((type & osMutexRobust) != osMutexRobust) { - mem = -1; - - if (attr != NULL) { - if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) { - /* The memory for control block is provided, use static object */ - mem = 1; - } - else { - if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) { - /* Control block will be allocated from the dynamic pool */ - mem = 0; - } - } - } - else { - mem = 0; - } - - if (mem == 1) { - #if (configSUPPORT_STATIC_ALLOCATION == 1) - if (rmtx != 0U) { - #if (configUSE_RECURSIVE_MUTEXES == 1) - hMutex = xSemaphoreCreateRecursiveMutexStatic (attr->cb_mem); - #endif - } - else { - hMutex = xSemaphoreCreateMutexStatic (attr->cb_mem); - } - #endif - } - else { - if (mem == 0) { - #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) - if (rmtx != 0U) { - #if (configUSE_RECURSIVE_MUTEXES == 1) - hMutex = xSemaphoreCreateRecursiveMutex (); - #endif - } else { - hMutex = xSemaphoreCreateMutex (); - } - #endif - } - } - - #if (configQUEUE_REGISTRY_SIZE > 0) - if (hMutex != NULL) { - if ((attr != NULL) && (attr->name != NULL)) { - /* Only non-NULL name objects are added to the Queue Registry */ - vQueueAddToRegistry (hMutex, attr->name); - } - } - #endif - - if ((hMutex != NULL) && (rmtx != 0U)) { - /* Set LSB as 'recursive mutex flag' */ - hMutex = (SemaphoreHandle_t)((uint32_t)hMutex | 1U); - } - } - } - - /* Return mutex ID */ - return ((osMutexId_t)hMutex); -} - -/* - Acquire a Mutex or timeout if it is locked. -*/ -osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) { - SemaphoreHandle_t hMutex; - osStatus_t stat; - uint32_t rmtx; - - hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U); - - /* Extract recursive mutex flag */ - rmtx = (uint32_t)mutex_id & 1U; - - stat = osOK; - - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if (hMutex == NULL) { - stat = osErrorParameter; - } - else { - if (rmtx != 0U) { - #if (configUSE_RECURSIVE_MUTEXES == 1) - if (xSemaphoreTakeRecursive (hMutex, timeout) != pdPASS) { - if (timeout != 0U) { - stat = osErrorTimeout; - } else { - stat = osErrorResource; - } - } - #endif - } - else { - if (xSemaphoreTake (hMutex, timeout) != pdPASS) { - if (timeout != 0U) { - stat = osErrorTimeout; - } else { - stat = osErrorResource; - } - } - } - } - - /* Return execution status */ - return (stat); -} - -/* - Release a Mutex that was acquired by osMutexAcquire. -*/ -osStatus_t osMutexRelease (osMutexId_t mutex_id) { - SemaphoreHandle_t hMutex; - osStatus_t stat; - uint32_t rmtx; - - hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U); - - /* Extract recursive mutex flag */ - rmtx = (uint32_t)mutex_id & 1U; - - stat = osOK; - - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if (hMutex == NULL) { - stat = osErrorParameter; - } - else { - if (rmtx != 0U) { - #if (configUSE_RECURSIVE_MUTEXES == 1) - if (xSemaphoreGiveRecursive (hMutex) != pdPASS) { - stat = osErrorResource; - } - #endif - } - else { - if (xSemaphoreGive (hMutex) != pdPASS) { - stat = osErrorResource; - } - } - } - - /* Return execution status */ - return (stat); -} - -/* - Get Thread which owns a Mutex object. -*/ -osThreadId_t osMutexGetOwner (osMutexId_t mutex_id) { - SemaphoreHandle_t hMutex; - osThreadId_t owner; - - hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U); - - if ((IRQ_Context() != 0U) || (hMutex == NULL)) { - owner = NULL; - } else { - owner = (osThreadId_t)xSemaphoreGetMutexHolder (hMutex); - } - - /* Return owner thread ID */ - return (owner); -} - -/* - Delete a Mutex object. -*/ -osStatus_t osMutexDelete (osMutexId_t mutex_id) { - osStatus_t stat; -#ifndef USE_FreeRTOS_HEAP_1 - SemaphoreHandle_t hMutex; - - hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U); - - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if (hMutex == NULL) { - stat = osErrorParameter; - } - else { - #if (configQUEUE_REGISTRY_SIZE > 0) - vQueueUnregisterQueue (hMutex); - #endif - stat = osOK; - vSemaphoreDelete (hMutex); - } -#else - stat = osError; -#endif - - /* Return execution status */ - return (stat); -} -#endif /* (configUSE_OS2_MUTEX == 1) */ - - -/* ==== Semaphore Management Functions ==== */ - -/* - Create and Initialize a Semaphore object. -*/ -osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) { - SemaphoreHandle_t hSemaphore; - int32_t mem; - - hSemaphore = NULL; - - if ((IRQ_Context() == 0U) && (max_count > 0U) && (initial_count <= max_count)) { - mem = -1; - - if (attr != NULL) { - if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) { - /* The memory for control block is provided, use static object */ - mem = 1; - } - else { - if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) { - /* Control block will be allocated from the dynamic pool */ - mem = 0; - } - } - } - else { - mem = 0; - } - - if (mem != -1) { - if (max_count == 1U) { - if (mem == 1) { - #if (configSUPPORT_STATIC_ALLOCATION == 1) - hSemaphore = xSemaphoreCreateBinaryStatic ((StaticSemaphore_t *)attr->cb_mem); - #endif - } - else { - #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) - hSemaphore = xSemaphoreCreateBinary(); - #endif - } - - if ((hSemaphore != NULL) && (initial_count != 0U)) { - if (xSemaphoreGive (hSemaphore) != pdPASS) { - vSemaphoreDelete (hSemaphore); - hSemaphore = NULL; - } - } - } - else { - if (mem == 1) { - #if (configSUPPORT_STATIC_ALLOCATION == 1) - hSemaphore = xSemaphoreCreateCountingStatic (max_count, initial_count, (StaticSemaphore_t *)attr->cb_mem); - #endif - } - else { - #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) - hSemaphore = xSemaphoreCreateCounting (max_count, initial_count); - #endif - } - } - - #if (configQUEUE_REGISTRY_SIZE > 0) - if (hSemaphore != NULL) { - if ((attr != NULL) && (attr->name != NULL)) { - /* Only non-NULL name objects are added to the Queue Registry */ - vQueueAddToRegistry (hSemaphore, attr->name); - } - } - #endif - } - } - - /* Return semaphore ID */ - return ((osSemaphoreId_t)hSemaphore); -} - -/* - Acquire a Semaphore token or timeout if no tokens are available. -*/ -osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) { - SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; - osStatus_t stat; - BaseType_t yield; - - stat = osOK; - - if (hSemaphore == NULL) { - stat = osErrorParameter; - } - else if (IRQ_Context() != 0U) { - if (timeout != 0U) { - stat = osErrorParameter; - } - else { - yield = pdFALSE; - - if (xSemaphoreTakeFromISR (hSemaphore, &yield) != pdPASS) { - stat = osErrorResource; - } else { - portYIELD_FROM_ISR (yield); - } - } - } - else { - if (xSemaphoreTake (hSemaphore, (TickType_t)timeout) != pdPASS) { - if (timeout != 0U) { - stat = osErrorTimeout; - } else { - stat = osErrorResource; - } - } - } - - /* Return execution status */ - return (stat); -} - -/* - Release a Semaphore token up to the initial maximum count. -*/ -osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id) { - SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; - osStatus_t stat; - BaseType_t yield; - - stat = osOK; - - if (hSemaphore == NULL) { - stat = osErrorParameter; - } - else if (IRQ_Context() != 0U) { - yield = pdFALSE; - - if (xSemaphoreGiveFromISR (hSemaphore, &yield) != pdTRUE) { - stat = osErrorResource; - } else { - portYIELD_FROM_ISR (yield); - } - } - else { - if (xSemaphoreGive (hSemaphore) != pdPASS) { - stat = osErrorResource; - } - } - - /* Return execution status */ - return (stat); -} - -/* - Get current Semaphore token count. -*/ -uint32_t osSemaphoreGetCount (osSemaphoreId_t semaphore_id) { - SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; - uint32_t count; - - if (hSemaphore == NULL) { - count = 0U; - } - else if (IRQ_Context() != 0U) { - count = (uint32_t)uxSemaphoreGetCountFromISR (hSemaphore); - } else { - count = (uint32_t)uxSemaphoreGetCount (hSemaphore); - } - - /* Return number of tokens */ - return (count); -} - -/* - Delete a Semaphore object. -*/ -osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id) { - SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; - osStatus_t stat; - -#ifndef USE_FreeRTOS_HEAP_1 - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if (hSemaphore == NULL) { - stat = osErrorParameter; - } - else { - #if (configQUEUE_REGISTRY_SIZE > 0) - vQueueUnregisterQueue (hSemaphore); - #endif - - stat = osOK; - vSemaphoreDelete (hSemaphore); - } -#else - stat = osError; -#endif - - /* Return execution status */ - return (stat); -} - - /* ==== Message Queue Management Functions ==== */ /* @@ -2301,498 +1070,6 @@ osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id) { return (stat); } - -/* ==== Memory Pool Management Functions ==== */ - -#ifdef FREERTOS_MPOOL_H_ -/* Static memory pool functions */ -static void FreeBlock (MemPool_t *mp, void *block); -static void *AllocBlock (MemPool_t *mp); -static void *CreateBlock (MemPool_t *mp); - -/* - Create and Initialize a Memory Pool object. -*/ -osMemoryPoolId_t osMemoryPoolNew (uint32_t block_count, uint32_t block_size, const osMemoryPoolAttr_t *attr) { - MemPool_t *mp; - const char *name; - int32_t mem_cb, mem_mp; - uint32_t sz; - - if (IRQ_Context() != 0U) { - mp = NULL; - } - else if ((block_count == 0U) || (block_size == 0U)) { - mp = NULL; - } - else { - mp = NULL; - sz = MEMPOOL_ARR_SIZE (block_count, block_size); - - name = NULL; - mem_cb = -1; - mem_mp = -1; - - if (attr != NULL) { - if (attr->name != NULL) { - name = attr->name; - } - - if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(MemPool_t))) { - /* Static control block is provided */ - mem_cb = 1; - } - else if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) { - /* Allocate control block memory on heap */ - mem_cb = 0; - } - - if ((attr->mp_mem == NULL) && (attr->mp_size == 0U)) { - /* Allocate memory array on heap */ - mem_mp = 0; - } - else { - if (attr->mp_mem != NULL) { - /* Check if array is 4-byte aligned */ - if (((uint32_t)attr->mp_mem & 3U) == 0U) { - /* Check if array big enough */ - if (attr->mp_size >= sz) { - /* Static memory pool array is provided */ - mem_mp = 1; - } - } - } - } - } - else { - /* Attributes not provided, allocate memory on heap */ - mem_cb = 0; - mem_mp = 0; - } - - if (mem_cb == 0) { - mp = pvPortMalloc (sizeof(MemPool_t)); - } else { - mp = attr->cb_mem; - } - - if (mp != NULL) { - /* Create a semaphore (max count == initial count == block_count) */ - #if (configSUPPORT_STATIC_ALLOCATION == 1) - mp->sem = xSemaphoreCreateCountingStatic (block_count, block_count, &mp->mem_sem); - #elif (configSUPPORT_DYNAMIC_ALLOCATION == 1) - mp->sem = xSemaphoreCreateCounting (block_count, block_count); - #else - mp->sem = NULL; - #endif - - if (mp->sem != NULL) { - /* Setup memory array */ - if (mem_mp == 0) { - mp->mem_arr = pvPortMalloc (sz); - } else { - mp->mem_arr = attr->mp_mem; - } - } - } - - if ((mp != NULL) && (mp->mem_arr != NULL)) { - /* Memory pool can be created */ - mp->head = NULL; - mp->mem_sz = sz; - mp->name = name; - mp->bl_sz = block_size; - mp->bl_cnt = block_count; - mp->n = 0U; - - /* Set heap allocated memory flags */ - mp->status = MPOOL_STATUS; - - if (mem_cb == 0) { - /* Control block on heap */ - mp->status |= 1U; - } - if (mem_mp == 0) { - /* Memory array on heap */ - mp->status |= 2U; - } - } - else { - /* Memory pool cannot be created, release allocated resources */ - if ((mem_cb == 0) && (mp != NULL)) { - /* Free control block memory */ - vPortFree (mp); - } - mp = NULL; - } - } - - /* Return memory pool ID */ - return (mp); -} - -/* - Get name of a Memory Pool object. -*/ -const char *osMemoryPoolGetName (osMemoryPoolId_t mp_id) { - MemPool_t *mp = (osMemoryPoolId_t)mp_id; - const char *p; - - if (IRQ_Context() != 0U) { - p = NULL; - } - else if (mp_id == NULL) { - p = NULL; - } - else { - p = mp->name; - } - - /* Return name as null-terminated string */ - return (p); -} - -/* - Allocate a memory block from a Memory Pool. -*/ -void *osMemoryPoolAlloc (osMemoryPoolId_t mp_id, uint32_t timeout) { - MemPool_t *mp; - void *block; - uint32_t isrm; - - if (mp_id == NULL) { - /* Invalid input parameters */ - block = NULL; - } - else { - block = NULL; - - mp = (MemPool_t *)mp_id; - - if ((mp->status & MPOOL_STATUS) == MPOOL_STATUS) { - if (IRQ_Context() != 0U) { - if (timeout == 0U) { - if (xSemaphoreTakeFromISR (mp->sem, NULL) == pdTRUE) { - if ((mp->status & MPOOL_STATUS) == MPOOL_STATUS) { - isrm = taskENTER_CRITICAL_FROM_ISR(); - - /* Get a block from the free-list */ - block = AllocBlock(mp); - - if (block == NULL) { - /* List of free blocks is empty, 'create' new block */ - block = CreateBlock(mp); - } - - taskEXIT_CRITICAL_FROM_ISR(isrm); - } - } - } - } - else { - if (xSemaphoreTake (mp->sem, (TickType_t)timeout) == pdTRUE) { - if ((mp->status & MPOOL_STATUS) == MPOOL_STATUS) { - taskENTER_CRITICAL(); - - /* Get a block from the free-list */ - block = AllocBlock(mp); - - if (block == NULL) { - /* List of free blocks is empty, 'create' new block */ - block = CreateBlock(mp); - } - - taskEXIT_CRITICAL(); - } - } - } - } - } - - /* Return memory block address */ - return (block); -} - -/* - Return an allocated memory block back to a Memory Pool. -*/ -osStatus_t osMemoryPoolFree (osMemoryPoolId_t mp_id, void *block) { - MemPool_t *mp; - osStatus_t stat; - uint32_t isrm; - BaseType_t yield; - - if ((mp_id == NULL) || (block == NULL)) { - /* Invalid input parameters */ - stat = osErrorParameter; - } - else { - mp = (MemPool_t *)mp_id; - - if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) { - /* Invalid object status */ - stat = osErrorResource; - } - else if ((block < (void *)&mp->mem_arr[0]) || (block > (void*)&mp->mem_arr[mp->mem_sz-1])) { - /* Block pointer outside of memory array area */ - stat = osErrorParameter; - } - else { - stat = osOK; - - if (IRQ_Context() != 0U) { - if (uxSemaphoreGetCountFromISR (mp->sem) == mp->bl_cnt) { - stat = osErrorResource; - } - else { - isrm = taskENTER_CRITICAL_FROM_ISR(); - - /* Add block to the list of free blocks */ - FreeBlock(mp, block); - - taskEXIT_CRITICAL_FROM_ISR(isrm); - - yield = pdFALSE; - xSemaphoreGiveFromISR (mp->sem, &yield); - portYIELD_FROM_ISR (yield); - } - } - else { - if (uxSemaphoreGetCount (mp->sem) == mp->bl_cnt) { - stat = osErrorResource; - } - else { - taskENTER_CRITICAL(); - - /* Add block to the list of free blocks */ - FreeBlock(mp, block); - - taskEXIT_CRITICAL(); - - xSemaphoreGive (mp->sem); - } - } - } - } - - /* Return execution status */ - return (stat); -} - -/* - Get maximum number of memory blocks in a Memory Pool. -*/ -uint32_t osMemoryPoolGetCapacity (osMemoryPoolId_t mp_id) { - MemPool_t *mp; - uint32_t n; - - if (mp_id == NULL) { - /* Invalid input parameters */ - n = 0U; - } - else { - mp = (MemPool_t *)mp_id; - - if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) { - /* Invalid object status */ - n = 0U; - } - else { - n = mp->bl_cnt; - } - } - - /* Return maximum number of memory blocks */ - return (n); -} - -/* - Get memory block size in a Memory Pool. -*/ -uint32_t osMemoryPoolGetBlockSize (osMemoryPoolId_t mp_id) { - MemPool_t *mp; - uint32_t sz; - - if (mp_id == NULL) { - /* Invalid input parameters */ - sz = 0U; - } - else { - mp = (MemPool_t *)mp_id; - - if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) { - /* Invalid object status */ - sz = 0U; - } - else { - sz = mp->bl_sz; - } - } - - /* Return memory block size in bytes */ - return (sz); -} - -/* - Get number of memory blocks used in a Memory Pool. -*/ -uint32_t osMemoryPoolGetCount (osMemoryPoolId_t mp_id) { - MemPool_t *mp; - uint32_t n; - - if (mp_id == NULL) { - /* Invalid input parameters */ - n = 0U; - } - else { - mp = (MemPool_t *)mp_id; - - if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) { - /* Invalid object status */ - n = 0U; - } - else { - if (IRQ_Context() != 0U) { - n = uxSemaphoreGetCountFromISR (mp->sem); - } else { - n = uxSemaphoreGetCount (mp->sem); - } - - n = mp->bl_cnt - n; - } - } - - /* Return number of memory blocks used */ - return (n); -} - -/* - Get number of memory blocks available in a Memory Pool. -*/ -uint32_t osMemoryPoolGetSpace (osMemoryPoolId_t mp_id) { - MemPool_t *mp; - uint32_t n; - - if (mp_id == NULL) { - /* Invalid input parameters */ - n = 0U; - } - else { - mp = (MemPool_t *)mp_id; - - if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) { - /* Invalid object status */ - n = 0U; - } - else { - if (IRQ_Context() != 0U) { - n = uxSemaphoreGetCountFromISR (mp->sem); - } else { - n = uxSemaphoreGetCount (mp->sem); - } - } - } - - /* Return number of memory blocks available */ - return (n); -} - -/* - Delete a Memory Pool object. -*/ -osStatus_t osMemoryPoolDelete (osMemoryPoolId_t mp_id) { - MemPool_t *mp; - osStatus_t stat; - - if (mp_id == NULL) { - /* Invalid input parameters */ - stat = osErrorParameter; - } - else if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else { - mp = (MemPool_t *)mp_id; - - taskENTER_CRITICAL(); - - /* Invalidate control block status */ - mp->status = mp->status & 3U; - - /* Wake-up tasks waiting for pool semaphore */ - while (xSemaphoreGive (mp->sem) == pdTRUE); - - mp->head = NULL; - mp->bl_sz = 0U; - mp->bl_cnt = 0U; - - if ((mp->status & 2U) != 0U) { - /* Memory pool array allocated on heap */ - vPortFree (mp->mem_arr); - } - if ((mp->status & 1U) != 0U) { - /* Memory pool control block allocated on heap */ - vPortFree (mp); - } - - taskEXIT_CRITICAL(); - - stat = osOK; - } - - /* Return execution status */ - return (stat); -} - -/* - Create new block given according to the current block index. -*/ -static void *CreateBlock (MemPool_t *mp) { - MemPoolBlock_t *p = NULL; - - if (mp->n < mp->bl_cnt) { - /* Unallocated blocks exist, set pointer to new block */ - p = (void *)(mp->mem_arr + (mp->bl_sz * mp->n)); - - /* Increment block index */ - mp->n += 1U; - } - - return (p); -} - -/* - Allocate a block by reading the list of free blocks. -*/ -static void *AllocBlock (MemPool_t *mp) { - MemPoolBlock_t *p = NULL; - - if (mp->head != NULL) { - /* List of free block exists, get head block */ - p = mp->head; - - /* Head block is now next on the list */ - mp->head = p->next; - } - - return (p); -} - -/* - Free block by putting it to the list of free blocks. -*/ -static void FreeBlock (MemPool_t *mp, void *block) { - MemPoolBlock_t *p = block; - - /* Store current head into block memory space */ - p->next = mp->head; - - /* Store current block as new head */ - mp->head = p; -} -#endif /* FREERTOS_MPOOL_H_ */ -/*---------------------------------------------------------------------------*/ - /* Callback function prototypes */ extern void vApplicationIdleHook (void); extern void vApplicationMallocFailedHook (void); @@ -2841,34 +1118,3 @@ __WEAK void vApplicationStackOverflowHook (TaskHandle_t xTask, char *pcTaskName) configASSERT(0); } #endif - -/*---------------------------------------------------------------------------*/ -#if (configSUPPORT_STATIC_ALLOCATION == 1) -/* - vApplicationGetIdleTaskMemory gets called when configSUPPORT_STATIC_ALLOCATION - equals to 1 and is required for static memory allocation support. -*/ -__WEAK void vApplicationGetIdleTaskMemory (StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) { - /* Idle task control block and stack */ - static StaticTask_t Idle_TCB; - static StackType_t Idle_Stack[configMINIMAL_STACK_SIZE]; - - *ppxIdleTaskTCBBuffer = &Idle_TCB; - *ppxIdleTaskStackBuffer = &Idle_Stack[0]; - *pulIdleTaskStackSize = (uint32_t)configMINIMAL_STACK_SIZE; -} - -/* - vApplicationGetTimerTaskMemory gets called when configSUPPORT_STATIC_ALLOCATION - equals to 1 and is required for static memory allocation support. -*/ -__WEAK void vApplicationGetTimerTaskMemory (StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize) { - /* Timer task control block and stack */ - static StaticTask_t Timer_TCB; - static StackType_t Timer_Stack[configTIMER_TASK_STACK_DEPTH]; - - *ppxTimerTaskTCBBuffer = &Timer_TCB; - *ppxTimerTaskStackBuffer = &Timer_Stack[0]; - *pulTimerTaskStackSize = (uint32_t)configTIMER_TASK_STACK_DEPTH; -} -#endif diff --git a/lib/FreeRTOS-glue/cmsis_os2.h b/lib/FreeRTOS-glue/cmsis_os2.h index 76612e29..044c9851 100644 --- a/lib/FreeRTOS-glue/cmsis_os2.h +++ b/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 -#include - + +#include + #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_ diff --git a/lib/FreeRTOS-glue/freertos_mpool.h b/lib/FreeRTOS-glue/freertos_mpool.h deleted file mode 100644 index cea5017e..00000000 --- a/lib/FreeRTOS-glue/freertos_mpool.h +++ /dev/null @@ -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 -#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_ */ diff --git a/lib/FreeRTOS-glue/freertos_os2.h b/lib/FreeRTOS-glue/freertos_os2.h index f67d2ae9..1e70b3fc 100644 --- a/lib/FreeRTOS-glue/freertos_os2.h +++ b/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_ */ diff --git a/lib/FreeRTOS-glue/os_tick.h b/lib/FreeRTOS-glue/os_tick.h deleted file mode 100644 index 3cfd8954..00000000 --- a/lib/FreeRTOS-glue/os_tick.h +++ /dev/null @@ -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 - -#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 */ diff --git a/lib/ST25RFAL002/platform.c b/lib/ST25RFAL002/platform.c index 52ac843e..c688bd59 100644 --- a/lib/ST25RFAL002/platform.c +++ b/lib/ST25RFAL002/platform.c @@ -3,49 +3,58 @@ #include #include -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) { diff --git a/lib/infrared/worker/infrared_worker.c b/lib/infrared/worker/infrared_worker.c index 71126c86..b24b7480 100644 --- a/lib/infrared/worker/infrared_worker.c +++ b/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); diff --git a/lib/subghz/subghz_file_encoder_worker.c b/lib/subghz/subghz_file_encoder_worker.c index 83cf90b7..0ec4c861 100644 --- a/lib/subghz/subghz_file_encoder_worker.c +++ b/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) {