[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
This commit is contained in:
		
							parent
							
								
									7618c8ba6f
								
							
						
					
					
						commit
						839e52ac32
					
				| @ -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) { | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -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); | ||||
| 
 | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -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); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -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
 | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -32,7 +32,7 @@ typedef struct { | ||||
| 
 | ||||
| /** Input state */ | ||||
| typedef struct { | ||||
|     osThreadId_t thread; | ||||
|     FuriThreadId thread_id; | ||||
|     FuriPubSub* event_pubsub; | ||||
|     InputPinState* pin_states; | ||||
|     Cli* cli; | ||||
|  | ||||
| @ -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( | ||||
|  | ||||
| @ -15,7 +15,7 @@ | ||||
| #include <assets_icons.h> | ||||
| 
 | ||||
| struct Loader { | ||||
|     osThreadId_t loader_thread; | ||||
|     FuriThreadId loader_thread; | ||||
| 
 | ||||
|     const FlipperApplication* application; | ||||
|     FuriThread* application_thread; | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -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
 | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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)); | ||||
|     */ | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -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); | ||||
| 
 | ||||
|  | ||||
| @ -6,16 +6,19 @@ | ||||
| 
 | ||||
| #include <cmsis_os2.h> | ||||
| 
 | ||||
| #include <furi/common_defines.h> | ||||
| #include <furi/check.h> | ||||
| #include <furi/common_defines.h> | ||||
| #include <furi/log.h> | ||||
| #include <furi/event_flags.h> | ||||
| #include <furi/memmgr.h> | ||||
| #include <furi/memmgr_heap.h> | ||||
| #include <furi/mutex.h> | ||||
| #include <furi/pubsub.h> | ||||
| #include <furi/record.h> | ||||
| #include <furi/semaphore.h> | ||||
| #include <furi/stdglue.h> | ||||
| #include <furi/thread.h> | ||||
| #include <furi/valuemutex.h> | ||||
| #include <furi/log.h> | ||||
| 
 | ||||
| #include <furi_hal_gpio.h> | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										45
									
								
								core/furi/base.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								core/furi/base.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| // FreeRTOS part
 | ||||
| #include <FreeRTOS.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| // Timeout value.
 | ||||
| #define osWaitForever 0xFFFFFFFFU ///< Wait forever timeout value.
 | ||||
| 
 | ||||
| // Flags options (\ref furi_thread_flags_wait and \ref osEventFlagsWait).
 | ||||
| #define osFlagsWaitAny 0x00000000U ///< Wait for any flag (default).
 | ||||
| #define osFlagsWaitAll 0x00000001U ///< Wait for all flags.
 | ||||
| #define osFlagsNoClear 0x00000002U ///< Do not clear flags which have been specified to wait for.
 | ||||
| 
 | ||||
| // Flags errors (returned by osThreadFlagsXxxx and osEventFlagsXxxx).
 | ||||
| #define osFlagsError 0x80000000U ///< Error indicator.
 | ||||
| #define osFlagsErrorUnknown 0xFFFFFFFFU ///< osError (-1).
 | ||||
| #define osFlagsErrorTimeout 0xFFFFFFFEU ///< osErrorTimeout (-2).
 | ||||
| #define osFlagsErrorResource 0xFFFFFFFDU ///< osErrorResource (-3).
 | ||||
| #define osFlagsErrorParameter 0xFFFFFFFCU ///< osErrorParameter (-4).
 | ||||
| #define osFlagsErrorISR 0xFFFFFFFAU ///< osErrorISR (-6).
 | ||||
| 
 | ||||
| /// Status code values returned by CMSIS-RTOS functions.
 | ||||
| typedef enum { | ||||
|     osOK = 0, ///< Operation completed successfully.
 | ||||
|     osError = -1, ///< Unspecified RTOS error: run-time error but no other error message fits.
 | ||||
|     osErrorTimeout = -2, ///< Operation not completed within the timeout period.
 | ||||
|     osErrorResource = -3, ///< Resource not available.
 | ||||
|     osErrorParameter = -4, ///< Parameter error.
 | ||||
|     osErrorNoMemory = | ||||
|         -5, ///< System is out of memory: it was impossible to allocate or reserve memory for the operation.
 | ||||
|     osErrorISR = | ||||
|         -6, ///< Not allowed in ISR context: the function cannot be called from interrupt service routines.
 | ||||
|     osStatusReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
 | ||||
| } osStatus_t; | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -6,11 +6,14 @@ | ||||
| #include <furi_hal_rtc.h> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| #include <FreeRTOS.h> | ||||
| #include <task.h> | ||||
| 
 | ||||
| void __furi_print_name() { | ||||
|     if(FURI_IS_ISR()) { | ||||
|         furi_hal_console_puts("[ISR] "); | ||||
|     } else { | ||||
|         const char* name = osThreadGetName(osThreadGetId()); | ||||
|         const char* name = pcTaskGetName(xTaskGetCurrentTaskHandle()); | ||||
|         if(name == NULL) { | ||||
|             furi_hal_console_puts("[main] "); | ||||
|         } else { | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #define FURI_NORETURN [[noreturn]] | ||||
|  | ||||
							
								
								
									
										222
									
								
								core/furi/event_flags.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								core/furi/event_flags.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,222 @@ | ||||
| #include "event_flags.h" | ||||
| #include "common_defines.h" | ||||
| 
 | ||||
| #include <event_groups.h> | ||||
| 
 | ||||
| #define MAX_BITS_EVENT_GROUPS 24U | ||||
| #define EVENT_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_EVENT_GROUPS) - 1U)) | ||||
| 
 | ||||
| osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t* attr) { | ||||
|     EventGroupHandle_t hEventGroup; | ||||
|     int32_t mem; | ||||
| 
 | ||||
|     hEventGroup = NULL; | ||||
| 
 | ||||
|     if(FURI_IS_IRQ_MODE() == 0U) { | ||||
|         mem = -1; | ||||
| 
 | ||||
|         if(attr != NULL) { | ||||
|             if((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticEventGroup_t))) { | ||||
|                 /* The memory for control block is provided, use static object */ | ||||
|                 mem = 1; | ||||
|             } else { | ||||
|                 if((attr->cb_mem == NULL) && (attr->cb_size == 0U)) { | ||||
|                     /* Control block will be allocated from the dynamic pool */ | ||||
|                     mem = 0; | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             mem = 0; | ||||
|         } | ||||
| 
 | ||||
|         if(mem == 1) { | ||||
| #if(configSUPPORT_STATIC_ALLOCATION == 1) | ||||
|             hEventGroup = xEventGroupCreateStatic(attr->cb_mem); | ||||
| #endif | ||||
|         } else { | ||||
|             if(mem == 0) { | ||||
| #if(configSUPPORT_DYNAMIC_ALLOCATION == 1) | ||||
|                 hEventGroup = xEventGroupCreate(); | ||||
| #endif | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* Return event flags ID */ | ||||
|     return ((osEventFlagsId_t)hEventGroup); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|   Set the specified Event Flags. | ||||
| 
 | ||||
|   Limitations: | ||||
|   - Event flags are limited to 24 bits. | ||||
| */ | ||||
| uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags) { | ||||
|     EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; | ||||
|     uint32_t rflags; | ||||
|     BaseType_t yield; | ||||
| 
 | ||||
|     if((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) { | ||||
|         rflags = (uint32_t)osErrorParameter; | ||||
|     } else if(FURI_IS_IRQ_MODE() != 0U) { | ||||
| #if(configUSE_OS2_EVENTFLAGS_FROM_ISR == 0) | ||||
|         (void)yield; | ||||
|         /* Enable timers and xTimerPendFunctionCall function to support osEventFlagsSet from ISR */ | ||||
|         rflags = (uint32_t)osErrorResource; | ||||
| #else | ||||
|         yield = pdFALSE; | ||||
| 
 | ||||
|         if(xEventGroupSetBitsFromISR(hEventGroup, (EventBits_t)flags, &yield) == pdFAIL) { | ||||
|             rflags = (uint32_t)osErrorResource; | ||||
|         } else { | ||||
|             rflags = flags; | ||||
|             portYIELD_FROM_ISR(yield); | ||||
|         } | ||||
| #endif | ||||
|     } else { | ||||
|         rflags = xEventGroupSetBits(hEventGroup, (EventBits_t)flags); | ||||
|     } | ||||
| 
 | ||||
|     /* Return event flags after setting */ | ||||
|     return (rflags); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|   Clear the specified Event Flags. | ||||
| 
 | ||||
|   Limitations: | ||||
|   - Event flags are limited to 24 bits. | ||||
| */ | ||||
| uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags) { | ||||
|     EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; | ||||
|     uint32_t rflags; | ||||
| 
 | ||||
|     if((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) { | ||||
|         rflags = (uint32_t)osErrorParameter; | ||||
|     } else if(FURI_IS_IRQ_MODE() != 0U) { | ||||
| #if(configUSE_OS2_EVENTFLAGS_FROM_ISR == 0) | ||||
|         /* Enable timers and xTimerPendFunctionCall function to support osEventFlagsSet from ISR */ | ||||
|         rflags = (uint32_t)osErrorResource; | ||||
| #else | ||||
|         rflags = xEventGroupGetBitsFromISR(hEventGroup); | ||||
| 
 | ||||
|         if(xEventGroupClearBitsFromISR(hEventGroup, (EventBits_t)flags) == pdFAIL) { | ||||
|             rflags = (uint32_t)osErrorResource; | ||||
|         } else { | ||||
|             /* xEventGroupClearBitsFromISR only registers clear operation in the timer command queue. */ | ||||
|             /* Yield is required here otherwise clear operation might not execute in the right order. */ | ||||
|             /* See https://github.com/FreeRTOS/FreeRTOS-Kernel/issues/93 for more info.               */ | ||||
|             portYIELD_FROM_ISR(pdTRUE); | ||||
|         } | ||||
| #endif | ||||
|     } else { | ||||
|         rflags = xEventGroupClearBits(hEventGroup, (EventBits_t)flags); | ||||
|     } | ||||
| 
 | ||||
|     /* Return event flags before clearing */ | ||||
|     return (rflags); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|   Get the current Event Flags. | ||||
| 
 | ||||
|   Limitations: | ||||
|   - Event flags are limited to 24 bits. | ||||
| */ | ||||
| uint32_t osEventFlagsGet(osEventFlagsId_t ef_id) { | ||||
|     EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; | ||||
|     uint32_t rflags; | ||||
| 
 | ||||
|     if(ef_id == NULL) { | ||||
|         rflags = 0U; | ||||
|     } else if(FURI_IS_IRQ_MODE() != 0U) { | ||||
|         rflags = xEventGroupGetBitsFromISR(hEventGroup); | ||||
|     } else { | ||||
|         rflags = xEventGroupGetBits(hEventGroup); | ||||
|     } | ||||
| 
 | ||||
|     /* Return current event flags */ | ||||
|     return (rflags); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|   Wait for one or more Event Flags to become signaled. | ||||
| 
 | ||||
|   Limitations: | ||||
|   - Event flags are limited to 24 bits. | ||||
|   - osEventFlagsWait cannot be called from an ISR. | ||||
| */ | ||||
| uint32_t | ||||
|     osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout) { | ||||
|     EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; | ||||
|     BaseType_t wait_all; | ||||
|     BaseType_t exit_clr; | ||||
|     uint32_t rflags; | ||||
| 
 | ||||
|     if((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) { | ||||
|         rflags = (uint32_t)osErrorParameter; | ||||
|     } else if(FURI_IS_IRQ_MODE() != 0U) { | ||||
|         rflags = (uint32_t)osErrorISR; | ||||
|     } else { | ||||
|         if(options & osFlagsWaitAll) { | ||||
|             wait_all = pdTRUE; | ||||
|         } else { | ||||
|             wait_all = pdFAIL; | ||||
|         } | ||||
| 
 | ||||
|         if(options & osFlagsNoClear) { | ||||
|             exit_clr = pdFAIL; | ||||
|         } else { | ||||
|             exit_clr = pdTRUE; | ||||
|         } | ||||
| 
 | ||||
|         rflags = xEventGroupWaitBits( | ||||
|             hEventGroup, (EventBits_t)flags, exit_clr, wait_all, (TickType_t)timeout); | ||||
| 
 | ||||
|         if(options & osFlagsWaitAll) { | ||||
|             if((flags & rflags) != flags) { | ||||
|                 if(timeout > 0U) { | ||||
|                     rflags = (uint32_t)osErrorTimeout; | ||||
|                 } else { | ||||
|                     rflags = (uint32_t)osErrorResource; | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             if((flags & rflags) == 0U) { | ||||
|                 if(timeout > 0U) { | ||||
|                     rflags = (uint32_t)osErrorTimeout; | ||||
|                 } else { | ||||
|                     rflags = (uint32_t)osErrorResource; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* Return event flags before clearing */ | ||||
|     return (rflags); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|   Delete an Event Flags object. | ||||
| */ | ||||
| osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id) { | ||||
|     EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; | ||||
|     osStatus_t stat; | ||||
| 
 | ||||
| #ifndef USE_FreeRTOS_HEAP_1 | ||||
|     if(FURI_IS_IRQ_MODE() != 0U) { | ||||
|         stat = osErrorISR; | ||||
|     } else if(hEventGroup == NULL) { | ||||
|         stat = osErrorParameter; | ||||
|     } else { | ||||
|         stat = osOK; | ||||
|         vEventGroupDelete(hEventGroup); | ||||
|     } | ||||
| #else | ||||
|     stat = osError; | ||||
| #endif | ||||
| 
 | ||||
|     /* Return execution status */ | ||||
|     return (stat); | ||||
| } | ||||
							
								
								
									
										63
									
								
								core/furi/event_flags.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								core/furi/event_flags.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "base.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /// Attributes structure for event flags.
 | ||||
| typedef struct { | ||||
|     const char* name; ///< name of the event flags
 | ||||
|     uint32_t attr_bits; ///< attribute bits
 | ||||
|     void* cb_mem; ///< memory for control block
 | ||||
|     uint32_t cb_size; ///< size of provided memory for control block
 | ||||
| } osEventFlagsAttr_t; | ||||
| 
 | ||||
| /// \details Event Flags ID identifies the event flags.
 | ||||
| typedef void* osEventFlagsId_t; | ||||
| 
 | ||||
| /// Create and Initialize an Event Flags object.
 | ||||
| /// \param[in]     attr          event flags attributes; NULL: default values.
 | ||||
| /// \return event flags ID for reference by other functions or NULL in case of error.
 | ||||
| osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t* attr); | ||||
| 
 | ||||
| /// Get name of an Event Flags object.
 | ||||
| /// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
 | ||||
| /// \return name as null-terminated string.
 | ||||
| const char* osEventFlagsGetName(osEventFlagsId_t ef_id); | ||||
| 
 | ||||
| /// Set the specified Event Flags.
 | ||||
| /// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
 | ||||
| /// \param[in]     flags         specifies the flags that shall be set.
 | ||||
| /// \return event flags after setting or error code if highest bit set.
 | ||||
| uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags); | ||||
| 
 | ||||
| /// Clear the specified Event Flags.
 | ||||
| /// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
 | ||||
| /// \param[in]     flags         specifies the flags that shall be cleared.
 | ||||
| /// \return event flags before clearing or error code if highest bit set.
 | ||||
| uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags); | ||||
| 
 | ||||
| /// Get the current Event Flags.
 | ||||
| /// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
 | ||||
| /// \return current event flags.
 | ||||
| uint32_t osEventFlagsGet(osEventFlagsId_t ef_id); | ||||
| 
 | ||||
| /// Wait for one or more Event Flags to become signaled.
 | ||||
| /// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
 | ||||
| /// \param[in]     flags         specifies the flags to wait for.
 | ||||
| /// \param[in]     options       specifies flags options (osFlagsXxxx).
 | ||||
| /// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
 | ||||
| /// \return event flags before clearing or error code if highest bit set.
 | ||||
| uint32_t | ||||
|     osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout); | ||||
| 
 | ||||
| /// Delete an Event Flags object.
 | ||||
| /// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -1,5 +1,6 @@ | ||||
| #include "log.h" | ||||
| #include "check.h" | ||||
| #include "mutex.h" | ||||
| #include <cmsis_os2.h> | ||||
| #include <furi_hal.h> | ||||
| 
 | ||||
|  | ||||
| @ -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 = ""; | ||||
|     } | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <cmsis_os2.h> | ||||
| #include "furi/thread.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| @ -18,13 +18,13 @@ extern "C" { | ||||
|  * | ||||
|  * @param      thread_id  - thread id to track | ||||
|  */ | ||||
| void memmgr_heap_enable_thread_trace(osThreadId_t thread_id); | ||||
| void memmgr_heap_enable_thread_trace(FuriThreadId taks_handle); | ||||
| 
 | ||||
| /** Memmgr heap disable thread allocation tracking
 | ||||
|  * | ||||
|  * @param      thread_id  - thread id to track | ||||
|  */ | ||||
| void memmgr_heap_disable_thread_trace(osThreadId_t thread_id); | ||||
| void memmgr_heap_disable_thread_trace(FuriThreadId taks_handle); | ||||
| 
 | ||||
| /** Memmgr heap get allocatred thread memory
 | ||||
|  * | ||||
| @ -32,7 +32,7 @@ void memmgr_heap_disable_thread_trace(osThreadId_t thread_id); | ||||
|  * | ||||
|  * @return     bytes allocated right now | ||||
|  */ | ||||
| size_t memmgr_heap_get_thread_memory(osThreadId_t thread_id); | ||||
| size_t memmgr_heap_get_thread_memory(FuriThreadId taks_handle); | ||||
| 
 | ||||
| /** Memmgr heap get the max contiguous block size on the heap
 | ||||
|  * | ||||
|  | ||||
							
								
								
									
										217
									
								
								core/furi/mutex.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								core/furi/mutex.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,217 @@ | ||||
| #include "mutex.h" | ||||
| #include "check.h" | ||||
| #include "common_defines.h" | ||||
| 
 | ||||
| #include <semphr.h> | ||||
| 
 | ||||
| osMutexId_t osMutexNew(const osMutexAttr_t* attr) { | ||||
|     SemaphoreHandle_t hMutex; | ||||
|     uint32_t type; | ||||
|     uint32_t rmtx; | ||||
|     int32_t mem; | ||||
| 
 | ||||
|     hMutex = NULL; | ||||
| 
 | ||||
|     if(FURI_IS_IRQ_MODE() == 0U) { | ||||
|         if(attr != NULL) { | ||||
|             type = attr->attr_bits; | ||||
|         } else { | ||||
|             type = 0U; | ||||
|         } | ||||
| 
 | ||||
|         if((type & osMutexRecursive) == osMutexRecursive) { | ||||
|             rmtx = 1U; | ||||
|         } else { | ||||
|             rmtx = 0U; | ||||
|         } | ||||
| 
 | ||||
|         if((type & osMutexRobust) != osMutexRobust) { | ||||
|             mem = -1; | ||||
| 
 | ||||
|             if(attr != NULL) { | ||||
|                 if((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) { | ||||
|                     /* The memory for control block is provided, use static object */ | ||||
|                     mem = 1; | ||||
|                 } else { | ||||
|                     if((attr->cb_mem == NULL) && (attr->cb_size == 0U)) { | ||||
|                         /* Control block will be allocated from the dynamic pool */ | ||||
|                         mem = 0; | ||||
|                     } | ||||
|                 } | ||||
|             } else { | ||||
|                 mem = 0; | ||||
|             } | ||||
| 
 | ||||
|             if(mem == 1) { | ||||
| #if(configSUPPORT_STATIC_ALLOCATION == 1) | ||||
|                 if(rmtx != 0U) { | ||||
| #if(configUSE_RECURSIVE_MUTEXES == 1) | ||||
|                     hMutex = xSemaphoreCreateRecursiveMutexStatic(attr->cb_mem); | ||||
| #endif | ||||
|                 } else { | ||||
|                     hMutex = xSemaphoreCreateMutexStatic(attr->cb_mem); | ||||
|                 } | ||||
| #endif | ||||
|             } else { | ||||
|                 if(mem == 0) { | ||||
| #if(configSUPPORT_DYNAMIC_ALLOCATION == 1) | ||||
|                     if(rmtx != 0U) { | ||||
| #if(configUSE_RECURSIVE_MUTEXES == 1) | ||||
|                         hMutex = xSemaphoreCreateRecursiveMutex(); | ||||
| #endif | ||||
|                     } else { | ||||
|                         hMutex = xSemaphoreCreateMutex(); | ||||
|                     } | ||||
| #endif | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
| #if(configQUEUE_REGISTRY_SIZE > 0) | ||||
|             if(hMutex != NULL) { | ||||
|                 if((attr != NULL) && (attr->name != NULL)) { | ||||
|                     /* Only non-NULL name objects are added to the Queue Registry */ | ||||
|                     vQueueAddToRegistry(hMutex, attr->name); | ||||
|                 } | ||||
|             } | ||||
| #endif | ||||
| 
 | ||||
|             if((hMutex != NULL) && (rmtx != 0U)) { | ||||
|                 /* Set LSB as 'recursive mutex flag' */ | ||||
|                 hMutex = (SemaphoreHandle_t)((uint32_t)hMutex | 1U); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* Return mutex ID */ | ||||
|     return ((osMutexId_t)hMutex); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|     Acquire a Mutex or timeout if it is locked. | ||||
| */ | ||||
| osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout) { | ||||
|     SemaphoreHandle_t hMutex; | ||||
|     osStatus_t stat; | ||||
|     uint32_t rmtx; | ||||
| 
 | ||||
|     hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U); | ||||
| 
 | ||||
|     /* Extract recursive mutex flag */ | ||||
|     rmtx = (uint32_t)mutex_id & 1U; | ||||
| 
 | ||||
|     stat = osOK; | ||||
| 
 | ||||
|     if(FURI_IS_IRQ_MODE() != 0U) { | ||||
|         stat = osErrorISR; | ||||
|     } else if(hMutex == NULL) { | ||||
|         stat = osErrorParameter; | ||||
|     } else { | ||||
|         if(rmtx != 0U) { | ||||
| #if(configUSE_RECURSIVE_MUTEXES == 1) | ||||
|             if(xSemaphoreTakeRecursive(hMutex, timeout) != pdPASS) { | ||||
|                 if(timeout != 0U) { | ||||
|                     stat = osErrorTimeout; | ||||
|                 } else { | ||||
|                     stat = osErrorResource; | ||||
|                 } | ||||
|             } | ||||
| #endif | ||||
|         } else { | ||||
|             if(xSemaphoreTake(hMutex, timeout) != pdPASS) { | ||||
|                 if(timeout != 0U) { | ||||
|                     stat = osErrorTimeout; | ||||
|                 } else { | ||||
|                     stat = osErrorResource; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* Return execution status */ | ||||
|     return (stat); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|     Release a Mutex that was acquired by osMutexAcquire. | ||||
| */ | ||||
| osStatus_t osMutexRelease(osMutexId_t mutex_id) { | ||||
|     SemaphoreHandle_t hMutex; | ||||
|     osStatus_t stat; | ||||
|     uint32_t rmtx; | ||||
| 
 | ||||
|     hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U); | ||||
| 
 | ||||
|     /* Extract recursive mutex flag */ | ||||
|     rmtx = (uint32_t)mutex_id & 1U; | ||||
| 
 | ||||
|     stat = osOK; | ||||
| 
 | ||||
|     if(FURI_IS_IRQ_MODE() != 0U) { | ||||
|         stat = osErrorISR; | ||||
|     } else if(hMutex == NULL) { | ||||
|         stat = osErrorParameter; | ||||
|     } else { | ||||
|         if(rmtx != 0U) { | ||||
| #if(configUSE_RECURSIVE_MUTEXES == 1) | ||||
|             if(xSemaphoreGiveRecursive(hMutex) != pdPASS) { | ||||
|                 stat = osErrorResource; | ||||
|             } | ||||
| #endif | ||||
|         } else { | ||||
|             if(xSemaphoreGive(hMutex) != pdPASS) { | ||||
|                 stat = osErrorResource; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* Return execution status */ | ||||
|     return (stat); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|     Get Thread which owns a Mutex object. | ||||
| */ | ||||
| FuriThreadId osMutexGetOwner(osMutexId_t mutex_id) { | ||||
|     SemaphoreHandle_t hMutex; | ||||
|     FuriThreadId owner; | ||||
| 
 | ||||
|     hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U); | ||||
| 
 | ||||
|     if((FURI_IS_IRQ_MODE() != 0U) || (hMutex == NULL)) { | ||||
|         owner = 0; | ||||
|     } else { | ||||
|         owner = (FuriThreadId)xSemaphoreGetMutexHolder(hMutex); | ||||
|     } | ||||
| 
 | ||||
|     /* Return owner thread ID */ | ||||
|     return (owner); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|     Delete a Mutex object. | ||||
| */ | ||||
| osStatus_t osMutexDelete(osMutexId_t mutex_id) { | ||||
|     osStatus_t stat; | ||||
| #ifndef USE_FreeRTOS_HEAP_1 | ||||
|     SemaphoreHandle_t hMutex; | ||||
| 
 | ||||
|     hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U); | ||||
| 
 | ||||
|     if(FURI_IS_IRQ_MODE() != 0U) { | ||||
|         stat = osErrorISR; | ||||
|     } else if(hMutex == NULL) { | ||||
|         stat = osErrorParameter; | ||||
|     } else { | ||||
| #if(configQUEUE_REGISTRY_SIZE > 0) | ||||
|         vQueueUnregisterQueue(hMutex); | ||||
| #endif | ||||
|         stat = osOK; | ||||
|         vSemaphoreDelete(hMutex); | ||||
|     } | ||||
| #else | ||||
|     stat = osError; | ||||
| #endif | ||||
| 
 | ||||
|     /* Return execution status */ | ||||
|     return (stat); | ||||
| } | ||||
							
								
								
									
										56
									
								
								core/furi/mutex.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								core/furi/mutex.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "base.h" | ||||
| #include "thread.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| // Mutex attributes (attr_bits in \ref osMutexAttr_t).
 | ||||
| #define osMutexRecursive 0x00000001U ///< Recursive mutex.
 | ||||
| #define osMutexPrioInherit 0x00000002U ///< Priority inherit protocol.
 | ||||
| #define osMutexRobust 0x00000008U ///< Robust mutex.
 | ||||
| 
 | ||||
| /// Attributes structure for mutex.
 | ||||
| typedef struct { | ||||
|     const char* name; ///< name of the mutex
 | ||||
|     uint32_t attr_bits; ///< attribute bits
 | ||||
|     void* cb_mem; ///< memory for control block
 | ||||
|     uint32_t cb_size; ///< size of provided memory for control block
 | ||||
| } osMutexAttr_t; | ||||
| 
 | ||||
| /// \details Mutex ID identifies the mutex.
 | ||||
| typedef void* osMutexId_t; | ||||
| 
 | ||||
| /// Create and Initialize a Mutex object.
 | ||||
| /// \param[in]     attr          mutex attributes; NULL: default values.
 | ||||
| /// \return mutex ID for reference by other functions or NULL in case of error.
 | ||||
| osMutexId_t osMutexNew(const osMutexAttr_t* attr); | ||||
| 
 | ||||
| /// Get name of a Mutex object.
 | ||||
| /// \param[in]     mutex_id      mutex ID obtained by \ref osMutexNew.
 | ||||
| /// \return name as null-terminated string.
 | ||||
| const char* osMutexGetName(osMutexId_t mutex_id); | ||||
| 
 | ||||
| /// Acquire a Mutex or timeout if it is locked.
 | ||||
| /// \param[in]     mutex_id      mutex ID obtained by \ref osMutexNew.
 | ||||
| /// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout); | ||||
| 
 | ||||
| /// Release a Mutex that was acquired by \ref osMutexAcquire.
 | ||||
| /// \param[in]     mutex_id      mutex ID obtained by \ref osMutexNew.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osMutexRelease(osMutexId_t mutex_id); | ||||
| 
 | ||||
| /// Delete a Mutex object.
 | ||||
| /// \param[in]     mutex_id      mutex ID obtained by \ref osMutexNew.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osMutexDelete(osMutexId_t mutex_id); | ||||
| 
 | ||||
| FuriThreadId osMutexGetOwner(osMutexId_t mutex_id); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -1,9 +1,9 @@ | ||||
| #include "pubsub.h" | ||||
| #include "memmgr.h" | ||||
| #include "check.h" | ||||
| #include "mutex.h" | ||||
| 
 | ||||
| #include <m-list.h> | ||||
| #include <cmsis_os2.h> | ||||
| 
 | ||||
| struct FuriPubSubSubscription { | ||||
|     FuriPubSubCallback callback; | ||||
|  | ||||
| @ -1,8 +1,9 @@ | ||||
| #include "record.h" | ||||
| #include "check.h" | ||||
| #include "memmgr.h" | ||||
| #include "mutex.h" | ||||
| #include "event_flags.h" | ||||
| 
 | ||||
| #include <cmsis_os2.h> | ||||
| #include <m-string.h> | ||||
| #include <m-dict.h> | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										190
									
								
								core/furi/semaphore.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								core/furi/semaphore.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,190 @@ | ||||
| #include "semaphore.h" | ||||
| #include "check.h" | ||||
| #include "common_defines.h" | ||||
| 
 | ||||
| #include <semphr.h> | ||||
| 
 | ||||
| osSemaphoreId_t | ||||
|     osSemaphoreNew(uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t* attr) { | ||||
|     SemaphoreHandle_t hSemaphore; | ||||
|     int32_t mem; | ||||
| 
 | ||||
|     hSemaphore = NULL; | ||||
| 
 | ||||
|     if((FURI_IS_IRQ_MODE() == 0U) && (max_count > 0U) && (initial_count <= max_count)) { | ||||
|         mem = -1; | ||||
| 
 | ||||
|         if(attr != NULL) { | ||||
|             if((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) { | ||||
|                 /* The memory for control block is provided, use static object */ | ||||
|                 mem = 1; | ||||
|             } else { | ||||
|                 if((attr->cb_mem == NULL) && (attr->cb_size == 0U)) { | ||||
|                     /* Control block will be allocated from the dynamic pool */ | ||||
|                     mem = 0; | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             mem = 0; | ||||
|         } | ||||
| 
 | ||||
|         if(mem != -1) { | ||||
|             if(max_count == 1U) { | ||||
|                 if(mem == 1) { | ||||
| #if(configSUPPORT_STATIC_ALLOCATION == 1) | ||||
|                     hSemaphore = xSemaphoreCreateBinaryStatic((StaticSemaphore_t*)attr->cb_mem); | ||||
| #endif | ||||
|                 } else { | ||||
| #if(configSUPPORT_DYNAMIC_ALLOCATION == 1) | ||||
|                     hSemaphore = xSemaphoreCreateBinary(); | ||||
| #endif | ||||
|                 } | ||||
| 
 | ||||
|                 if((hSemaphore != NULL) && (initial_count != 0U)) { | ||||
|                     if(xSemaphoreGive(hSemaphore) != pdPASS) { | ||||
|                         vSemaphoreDelete(hSemaphore); | ||||
|                         hSemaphore = NULL; | ||||
|                     } | ||||
|                 } | ||||
|             } else { | ||||
|                 if(mem == 1) { | ||||
| #if(configSUPPORT_STATIC_ALLOCATION == 1) | ||||
|                     hSemaphore = xSemaphoreCreateCountingStatic( | ||||
|                         max_count, initial_count, (StaticSemaphore_t*)attr->cb_mem); | ||||
| #endif | ||||
|                 } else { | ||||
| #if(configSUPPORT_DYNAMIC_ALLOCATION == 1) | ||||
|                     hSemaphore = xSemaphoreCreateCounting(max_count, initial_count); | ||||
| #endif | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
| #if(configQUEUE_REGISTRY_SIZE > 0) | ||||
|             if(hSemaphore != NULL) { | ||||
|                 if((attr != NULL) && (attr->name != NULL)) { | ||||
|                     /* Only non-NULL name objects are added to the Queue Registry */ | ||||
|                     vQueueAddToRegistry(hSemaphore, attr->name); | ||||
|                 } | ||||
|             } | ||||
| #endif | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* Return semaphore ID */ | ||||
|     return ((osSemaphoreId_t)hSemaphore); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|     Acquire a Semaphore token or timeout if no tokens are available. | ||||
| */ | ||||
| osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout) { | ||||
|     SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; | ||||
|     osStatus_t stat; | ||||
|     BaseType_t yield; | ||||
| 
 | ||||
|     stat = osOK; | ||||
| 
 | ||||
|     if(hSemaphore == NULL) { | ||||
|         stat = osErrorParameter; | ||||
|     } else if(FURI_IS_IRQ_MODE() != 0U) { | ||||
|         if(timeout != 0U) { | ||||
|             stat = osErrorParameter; | ||||
|         } else { | ||||
|             yield = pdFALSE; | ||||
| 
 | ||||
|             if(xSemaphoreTakeFromISR(hSemaphore, &yield) != pdPASS) { | ||||
|                 stat = osErrorResource; | ||||
|             } else { | ||||
|                 portYIELD_FROM_ISR(yield); | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         if(xSemaphoreTake(hSemaphore, (TickType_t)timeout) != pdPASS) { | ||||
|             if(timeout != 0U) { | ||||
|                 stat = osErrorTimeout; | ||||
|             } else { | ||||
|                 stat = osErrorResource; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* Return execution status */ | ||||
|     return (stat); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|     Release a Semaphore token up to the initial maximum count. | ||||
| */ | ||||
| osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id) { | ||||
|     SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; | ||||
|     osStatus_t stat; | ||||
|     BaseType_t yield; | ||||
| 
 | ||||
|     stat = osOK; | ||||
| 
 | ||||
|     if(hSemaphore == NULL) { | ||||
|         stat = osErrorParameter; | ||||
|     } else if(FURI_IS_IRQ_MODE() != 0U) { | ||||
|         yield = pdFALSE; | ||||
| 
 | ||||
|         if(xSemaphoreGiveFromISR(hSemaphore, &yield) != pdTRUE) { | ||||
|             stat = osErrorResource; | ||||
|         } else { | ||||
|             portYIELD_FROM_ISR(yield); | ||||
|         } | ||||
|     } else { | ||||
|         if(xSemaphoreGive(hSemaphore) != pdPASS) { | ||||
|             stat = osErrorResource; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* Return execution status */ | ||||
|     return (stat); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|     Get current Semaphore token count. | ||||
| */ | ||||
| uint32_t osSemaphoreGetCount(osSemaphoreId_t semaphore_id) { | ||||
|     SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; | ||||
|     uint32_t count; | ||||
| 
 | ||||
|     if(hSemaphore == NULL) { | ||||
|         count = 0U; | ||||
|     } else if(FURI_IS_IRQ_MODE() != 0U) { | ||||
|         count = (uint32_t)uxSemaphoreGetCountFromISR(hSemaphore); | ||||
|     } else { | ||||
|         count = (uint32_t)uxSemaphoreGetCount(hSemaphore); | ||||
|     } | ||||
| 
 | ||||
|     /* Return number of tokens */ | ||||
|     return (count); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|     Delete a Semaphore object. | ||||
| */ | ||||
| osStatus_t osSemaphoreDelete(osSemaphoreId_t semaphore_id) { | ||||
|     SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; | ||||
|     osStatus_t stat; | ||||
| 
 | ||||
| #ifndef USE_FreeRTOS_HEAP_1 | ||||
|     if(FURI_IS_IRQ_MODE() != 0U) { | ||||
|         stat = osErrorISR; | ||||
|     } else if(hSemaphore == NULL) { | ||||
|         stat = osErrorParameter; | ||||
|     } else { | ||||
| #if(configQUEUE_REGISTRY_SIZE > 0) | ||||
|         vQueueUnregisterQueue(hSemaphore); | ||||
| #endif | ||||
| 
 | ||||
|         stat = osOK; | ||||
|         vSemaphoreDelete(hSemaphore); | ||||
|     } | ||||
| #else | ||||
|     stat = osError; | ||||
| #endif | ||||
| 
 | ||||
|     /* Return execution status */ | ||||
|     return (stat); | ||||
| } | ||||
							
								
								
									
										57
									
								
								core/furi/semaphore.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								core/furi/semaphore.h
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| @ -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; | ||||
|  | ||||
| @ -2,7 +2,9 @@ | ||||
| #include "memmgr.h" | ||||
| #include "memmgr_heap.h" | ||||
| #include "check.h" | ||||
| #include "common_defines.h" | ||||
| 
 | ||||
| #include <task.h> | ||||
| #include <m-string.h> | ||||
| 
 | ||||
| struct FuriThread { | ||||
| @ -15,14 +17,22 @@ struct FuriThread { | ||||
|     FuriThreadStateCallback state_callback; | ||||
|     void* state_context; | ||||
| 
 | ||||
|     osThreadAttr_t attr; | ||||
|     volatile osThreadId_t id; | ||||
|     char* name; | ||||
|     configSTACK_DEPTH_TYPE stack_size; | ||||
|     FuriThreadPriority priority; | ||||
| 
 | ||||
|     TaskHandle_t task_handle; | ||||
|     bool heap_trace_enabled; | ||||
|     size_t heap_size; | ||||
| }; | ||||
| 
 | ||||
| void furi_thread_set_state(FuriThread* thread, FuriThreadState state) { | ||||
| /** Catch threads that are trying to exit wrong way */ | ||||
| __attribute__((__noreturn__)) void furi_thread_catch() { | ||||
|     asm volatile("nop"); // extra magic
 | ||||
|     furi_crash("You are doing it wrong"); | ||||
| } | ||||
| 
 | ||||
| static void furi_thread_set_state(FuriThread* thread, FuriThreadState state) { | ||||
|     furi_assert(thread); | ||||
|     thread->state = state; | ||||
|     if(thread->state_callback) { | ||||
| @ -37,23 +47,24 @@ static void furi_thread_body(void* context) { | ||||
|     furi_assert(thread->state == FuriThreadStateStarting); | ||||
|     furi_thread_set_state(thread, FuriThreadStateRunning); | ||||
| 
 | ||||
|     osThreadId_t thread_id = osThreadGetId(); | ||||
|     TaskHandle_t task_handle = xTaskGetCurrentTaskHandle(); | ||||
|     if(thread->heap_trace_enabled == true) { | ||||
|         memmgr_heap_enable_thread_trace(thread_id); | ||||
|         memmgr_heap_enable_thread_trace((FuriThreadId)task_handle); | ||||
|     } | ||||
| 
 | ||||
|     thread->ret = thread->callback(thread->context); | ||||
| 
 | ||||
|     if(thread->heap_trace_enabled == true) { | ||||
|         osDelay(33); | ||||
|         thread->heap_size = memmgr_heap_get_thread_memory(thread_id); | ||||
|         memmgr_heap_disable_thread_trace(thread_id); | ||||
|         thread->heap_size = memmgr_heap_get_thread_memory((FuriThreadId)task_handle); | ||||
|         memmgr_heap_disable_thread_trace((FuriThreadId)task_handle); | ||||
|     } | ||||
| 
 | ||||
|     furi_assert(thread->state == FuriThreadStateRunning); | ||||
|     furi_thread_set_state(thread, FuriThreadStateStopped); | ||||
| 
 | ||||
|     osThreadExit(); | ||||
|     vTaskDelete(thread->task_handle); | ||||
|     furi_thread_catch(); | ||||
| } | ||||
| 
 | ||||
| FuriThread* furi_thread_alloc() { | ||||
| @ -66,21 +77,22 @@ void furi_thread_free(FuriThread* thread) { | ||||
|     furi_assert(thread); | ||||
|     furi_assert(thread->state == FuriThreadStateStopped); | ||||
| 
 | ||||
|     if(thread->attr.name) free((void*)thread->attr.name); | ||||
|     if(thread->name) free((void*)thread->name); | ||||
|     free(thread); | ||||
| } | ||||
| 
 | ||||
| void furi_thread_set_name(FuriThread* thread, const char* name) { | ||||
|     furi_assert(thread); | ||||
|     furi_assert(thread->state == FuriThreadStateStopped); | ||||
|     if(thread->attr.name) free((void*)thread->attr.name); | ||||
|     thread->attr.name = strdup(name); | ||||
|     if(thread->name) free((void*)thread->name); | ||||
|     thread->name = strdup(name); | ||||
| } | ||||
| 
 | ||||
| void furi_thread_set_stack_size(FuriThread* thread, size_t stack_size) { | ||||
|     furi_assert(thread); | ||||
|     furi_assert(thread->state == FuriThreadStateStopped); | ||||
|     thread->attr.stack_size = stack_size; | ||||
|     furi_assert(stack_size % 4 == 0); | ||||
|     thread->stack_size = stack_size; | ||||
| } | ||||
| 
 | ||||
| void furi_thread_set_callback(FuriThread* thread, FuriThreadCallback callback) { | ||||
| @ -95,6 +107,13 @@ void furi_thread_set_context(FuriThread* thread, void* context) { | ||||
|     thread->context = context; | ||||
| } | ||||
| 
 | ||||
| void furi_thread_set_priority(FuriThread* thread, FuriThreadPriority priority) { | ||||
|     furi_assert(thread); | ||||
|     furi_assert(thread->state == FuriThreadStateStopped); | ||||
|     furi_assert(priority >= FuriThreadPriorityIdle && priority <= FuriThreadPriorityIsr); | ||||
|     thread->priority = priority; | ||||
| } | ||||
| 
 | ||||
| void furi_thread_set_state_callback(FuriThread* thread, FuriThreadStateCallback callback) { | ||||
|     furi_assert(thread); | ||||
|     furi_assert(thread->state == FuriThreadStateStopped); | ||||
| @ -112,41 +131,39 @@ FuriThreadState furi_thread_get_state(FuriThread* thread) { | ||||
|     return thread->state; | ||||
| } | ||||
| 
 | ||||
| bool furi_thread_start(FuriThread* thread) { | ||||
| void furi_thread_start(FuriThread* thread) { | ||||
|     furi_assert(thread); | ||||
|     furi_assert(thread->callback); | ||||
|     furi_assert(thread->state == FuriThreadStateStopped); | ||||
|     furi_assert(thread->attr.stack_size > 0); | ||||
|     furi_assert(thread->stack_size > 0 && thread->stack_size < 0xFFFF * 4); | ||||
| 
 | ||||
|     furi_thread_set_state(thread, FuriThreadStateStarting); | ||||
|     thread->id = osThreadNew(furi_thread_body, thread, &thread->attr); | ||||
|     if(thread->id) { | ||||
|         return true; | ||||
|     } else { | ||||
|         furi_assert(thread->state == FuriThreadStateStarting); | ||||
|         furi_thread_set_state(thread, FuriThreadStateStopped); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     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); | ||||
| } | ||||
|  | ||||
| @ -5,9 +5,7 @@ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <cmsis_os2.h> | ||||
| #include "base.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| @ -20,9 +18,24 @@ typedef enum { | ||||
|     FuriThreadStateRunning, | ||||
| } FuriThreadState; | ||||
| 
 | ||||
| /** FuriThreadPriority */ | ||||
| typedef enum { | ||||
|     FuriThreadPriorityNone = 0, /**< Uninitialized, choose system default */ | ||||
|     FuriThreadPriorityIdle = 1, /**< Idle priority */ | ||||
|     FuriThreadPriorityLowest = 14, /**< Lowest */ | ||||
|     FuriThreadPriorityLow = 15, /**< Low */ | ||||
|     FuriThreadPriorityNormal = 16, /**< Normal */ | ||||
|     FuriThreadPriorityHigh = 17, /**< High */ | ||||
|     FuriThreadPriorityHighest = 18, /**< Highest */ | ||||
|     FuriThreadPriorityIsr = 32, /**< Deffered Isr (highest possible) */ | ||||
| } FuriThreadPriority; | ||||
| 
 | ||||
| /** FuriThread anonymous structure */ | ||||
| typedef struct FuriThread FuriThread; | ||||
| 
 | ||||
| /** FuriThreadId proxy type to OS low level functions */ | ||||
| typedef void* FuriThreadId; | ||||
| 
 | ||||
| /** FuriThreadCallback Your callback to run in new thread
 | ||||
|  * @warning    never use osThreadExit in FuriThread | ||||
|  */ | ||||
| @ -74,6 +87,13 @@ void furi_thread_set_callback(FuriThread* thread, FuriThreadCallback callback); | ||||
|  */ | ||||
| void furi_thread_set_context(FuriThread* thread, void* context); | ||||
| 
 | ||||
| /** Set FuriThread priority
 | ||||
|  * | ||||
|  * @param      thread   FuriThread instance | ||||
|  * @param      priority FuriThreadPriority value | ||||
|  */ | ||||
| void furi_thread_set_priority(FuriThread* thread, FuriThreadPriority priority); | ||||
| 
 | ||||
| /** Set FuriThread state change callback
 | ||||
|  * | ||||
|  * @param      thread    FuriThread instance | ||||
| @ -99,36 +119,24 @@ FuriThreadState furi_thread_get_state(FuriThread* thread); | ||||
| /** Start FuriThread
 | ||||
|  * | ||||
|  * @param      thread  FuriThread instance | ||||
|  * | ||||
|  * @return     true on success | ||||
|  */ | ||||
| bool furi_thread_start(FuriThread* thread); | ||||
| 
 | ||||
| /** Treminate FuriThread
 | ||||
|  * | ||||
|  * @param      thread  FuriThread instance | ||||
|  * | ||||
|  * @return     osStatus_t | ||||
|  * @warning    terminating statefull thread is dangerous use only if you know | ||||
|  *             what you doing | ||||
|  */ | ||||
| osStatus_t furi_thread_terminate(FuriThread* thread); | ||||
| void furi_thread_start(FuriThread* thread); | ||||
| 
 | ||||
| /** Join FuriThread
 | ||||
|  * | ||||
|  * @param      thread  FuriThread instance | ||||
|  * | ||||
|  * @return     osStatus_t | ||||
|  * @return     bool | ||||
|  */ | ||||
| osStatus_t furi_thread_join(FuriThread* thread); | ||||
| bool furi_thread_join(FuriThread* thread); | ||||
| 
 | ||||
| /** Get CMSIS Thread ID
 | ||||
| /** Get FreeRTOS FuriThreadId for FuriThread instance
 | ||||
|  * | ||||
|  * @param      thread  FuriThread instance | ||||
|  * | ||||
|  * @return     osThreadId_t or NULL | ||||
|  * @return     FuriThreadId or NULL | ||||
|  */ | ||||
| osThreadId_t furi_thread_get_thread_id(FuriThread* thread); | ||||
| FuriThreadId furi_thread_get_id(FuriThread* thread); | ||||
| 
 | ||||
| /** Enable heap tracing
 | ||||
|  * | ||||
| @ -158,6 +166,33 @@ size_t furi_thread_get_heap_size(FuriThread* thread); | ||||
|  */ | ||||
| int32_t furi_thread_get_return_code(FuriThread* thread); | ||||
| 
 | ||||
| /** Thread releated methods that doesn't involve FuriThread directly */ | ||||
| 
 | ||||
| /** Get FreeRTOS FuriThreadId for current thread
 | ||||
|  * | ||||
|  * @param      thread  FuriThread instance | ||||
|  * | ||||
|  * @return     FuriThreadId or NULL | ||||
|  */ | ||||
| FuriThreadId furi_thread_get_current_id(); | ||||
| 
 | ||||
| /** Return control to scheduler */ | ||||
| void furi_thread_yield(); | ||||
| 
 | ||||
| uint32_t furi_thread_flags_set(FuriThreadId thread_id, uint32_t flags); | ||||
| 
 | ||||
| uint32_t furi_thread_flags_clear(uint32_t flags); | ||||
| 
 | ||||
| uint32_t furi_thread_flags_get(void); | ||||
| 
 | ||||
| uint32_t furi_thread_flags_wait(uint32_t flags, uint32_t options, uint32_t timeout); | ||||
| 
 | ||||
| uint32_t furi_thread_enumerate(FuriThreadId* thread_array, uint32_t array_items); | ||||
| 
 | ||||
| const char* furi_thread_get_name(FuriThreadId thread_id); | ||||
| 
 | ||||
| uint32_t furi_thread_get_stack_space(FuriThreadId thread_id); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| 
 | ||||
| #include <cmsis_os2.h> | ||||
| #include <stdbool.h> | ||||
| #include "mutex.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -7,19 +7,16 @@ | ||||
| 
 | ||||
| #define TAG "Main" | ||||
| 
 | ||||
| static const osThreadAttr_t init_thread_attr = { | ||||
|     .name = "Init", | ||||
|     .stack_size = 4096, | ||||
| }; | ||||
| int32_t init_task(void* context) { | ||||
|     UNUSED(context); | ||||
| 
 | ||||
| void init_task() { | ||||
|     // Flipper FURI HAL
 | ||||
|     furi_hal_init(); | ||||
| 
 | ||||
|     // Init flipper
 | ||||
|     flipper_init(); | ||||
| 
 | ||||
|     osThreadExit(); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int main() { | ||||
| @ -29,8 +26,13 @@ int main() { | ||||
|     // Flipper critical FURI HAL
 | ||||
|     furi_hal_init_early(); | ||||
| 
 | ||||
|     FuriThread* main_thread = furi_thread_alloc(); | ||||
|     furi_thread_set_name(main_thread, "Init"); | ||||
|     furi_thread_set_stack_size(main_thread, 4096); | ||||
|     furi_thread_set_callback(main_thread, init_task); | ||||
| 
 | ||||
| #ifdef FURI_RAM_EXEC | ||||
|     osThreadNew(init_task, NULL, &init_thread_attr); | ||||
|     furi_thread_start(main_thread); | ||||
| #else | ||||
|     furi_hal_light_sequence("RGB"); | ||||
| 
 | ||||
| @ -52,7 +54,7 @@ int main() { | ||||
|         furi_hal_power_reset(); | ||||
|     } else { | ||||
|         furi_hal_light_sequence("rgb G"); | ||||
|         osThreadNew(init_task, NULL, &init_thread_attr); | ||||
|         furi_thread_start(main_thread); | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
|  | ||||
| @ -6,6 +6,7 @@ | ||||
| #include "gap.h" | ||||
| 
 | ||||
| #include <furi_hal.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #define TAG "Bt" | ||||
| 
 | ||||
| @ -106,9 +107,9 @@ void ble_app_get_key_storage_buff(uint8_t** addr, uint16_t* size) { | ||||
| 
 | ||||
| void ble_app_thread_stop() { | ||||
|     if(ble_app) { | ||||
|         osThreadId_t thread_id = furi_thread_get_thread_id(ble_app->thread); | ||||
|         FuriThreadId thread_id = furi_thread_get_id(ble_app->thread); | ||||
|         furi_assert(thread_id); | ||||
|         osThreadFlagsSet(thread_id, BLE_APP_FLAG_KILL_THREAD); | ||||
|         furi_thread_flags_set(thread_id, BLE_APP_FLAG_KILL_THREAD); | ||||
|         furi_thread_join(ble_app->thread); | ||||
|         furi_thread_free(ble_app->thread); | ||||
|         // Free resources
 | ||||
| @ -125,7 +126,7 @@ static int32_t ble_app_hci_thread(void* arg) { | ||||
|     uint32_t flags = 0; | ||||
| 
 | ||||
|     while(1) { | ||||
|         flags = osThreadFlagsWait(BLE_APP_FLAG_ALL, osFlagsWaitAny, osWaitForever); | ||||
|         flags = furi_thread_flags_wait(BLE_APP_FLAG_ALL, osFlagsWaitAny, osWaitForever); | ||||
|         if(flags & BLE_APP_FLAG_KILL_THREAD) { | ||||
|             break; | ||||
|         } | ||||
| @ -141,9 +142,9 @@ static int32_t ble_app_hci_thread(void* arg) { | ||||
| void hci_notify_asynch_evt(void* pdata) { | ||||
|     UNUSED(pdata); | ||||
|     if(ble_app) { | ||||
|         osThreadId_t thread_id = furi_thread_get_thread_id(ble_app->thread); | ||||
|         FuriThreadId thread_id = furi_thread_get_id(ble_app->thread); | ||||
|         furi_assert(thread_id); | ||||
|         osThreadFlagsSet(thread_id, BLE_APP_FLAG_HCI_EVENT); | ||||
|         furi_thread_flags_set(thread_id, BLE_APP_FLAG_HCI_EVENT); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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 */ | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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); | ||||
| 
 | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -43,10 +43,10 @@ | ||||
|  * Version 2.0.0 | ||||
|  *    Initial Release | ||||
|  *---------------------------------------------------------------------------*/ | ||||
|   | ||||
| 
 | ||||
| #ifndef CMSIS_OS2_H_ | ||||
| #define CMSIS_OS2_H_ | ||||
|   | ||||
| 
 | ||||
| #ifndef __NO_RETURN | ||||
| #if   defined(__CC_ARM) | ||||
| #define __NO_RETURN __declspec(noreturn) | ||||
| @ -60,24 +60,23 @@ | ||||
| #define __NO_RETURN | ||||
| #endif | ||||
| #endif | ||||
|   | ||||
| #include <stdint.h> | ||||
| #include <stddef.h> | ||||
|   | ||||
| 
 | ||||
| #include <furi/base.h> | ||||
| 
 | ||||
| #ifdef  __cplusplus | ||||
| extern "C" | ||||
| { | ||||
| #endif | ||||
|   | ||||
|   | ||||
| 
 | ||||
| 
 | ||||
| //  ==== Enumerations, structures, defines ====
 | ||||
|   | ||||
| 
 | ||||
| /// Version information.
 | ||||
| typedef struct { | ||||
|   uint32_t                       api;   ///< API version (major.minor.rev: mmnnnrrrr dec).
 | ||||
|   uint32_t                    kernel;   ///< Kernel version (major.minor.rev: mmnnnrrrr dec).
 | ||||
| } osVersion_t; | ||||
|   | ||||
| 
 | ||||
| /// Kernel state.
 | ||||
| typedef enum { | ||||
|   osKernelInactive        =  0,         ///< Inactive.
 | ||||
| @ -88,167 +87,31 @@ typedef enum { | ||||
|   osKernelError           = -1,         ///< Error.
 | ||||
|   osKernelReserved        = 0x7FFFFFFF  ///< Prevents enum down-size compiler optimization.
 | ||||
| } osKernelState_t; | ||||
|   | ||||
| /// Thread state.
 | ||||
| typedef enum { | ||||
|   osThreadInactive        =  0,         ///< Inactive.
 | ||||
|   osThreadReady           =  1,         ///< Ready.
 | ||||
|   osThreadRunning         =  2,         ///< Running.
 | ||||
|   osThreadBlocked         =  3,         ///< Blocked.
 | ||||
|   osThreadTerminated      =  4,         ///< Terminated.
 | ||||
|   osThreadError           = -1,         ///< Error.
 | ||||
|   osThreadReserved        = 0x7FFFFFFF  ///< Prevents enum down-size compiler optimization.
 | ||||
| } osThreadState_t; | ||||
|   | ||||
| /// Priority values.
 | ||||
| typedef enum { | ||||
|   osPriorityNone          =  0,         ///< No priority (not initialized).
 | ||||
|   osPriorityIdle          =  1,         ///< Reserved for Idle thread.
 | ||||
|   osPriorityLow           =  8,         ///< Priority: low
 | ||||
|   osPriorityLow1          =  8+1,       ///< Priority: low + 1
 | ||||
|   osPriorityLow2          =  8+2,       ///< Priority: low + 2
 | ||||
|   osPriorityLow3          =  8+3,       ///< Priority: low + 3
 | ||||
|   osPriorityLow4          =  8+4,       ///< Priority: low + 4
 | ||||
|   osPriorityLow5          =  8+5,       ///< Priority: low + 5
 | ||||
|   osPriorityLow6          =  8+6,       ///< Priority: low + 6
 | ||||
|   osPriorityLow7          =  8+7,       ///< Priority: low + 7
 | ||||
|   osPriorityBelowNormal   = 16,         ///< Priority: below normal
 | ||||
|   osPriorityBelowNormal1  = 16+1,       ///< Priority: below normal + 1
 | ||||
|   osPriorityBelowNormal2  = 16+2,       ///< Priority: below normal + 2
 | ||||
|   osPriorityBelowNormal3  = 16+3,       ///< Priority: below normal + 3
 | ||||
|   osPriorityBelowNormal4  = 16+4,       ///< Priority: below normal + 4
 | ||||
|   osPriorityBelowNormal5  = 16+5,       ///< Priority: below normal + 5
 | ||||
|   osPriorityBelowNormal6  = 16+6,       ///< Priority: below normal + 6
 | ||||
|   osPriorityBelowNormal7  = 16+7,       ///< Priority: below normal + 7
 | ||||
|   osPriorityNormal        = 24,         ///< Priority: normal
 | ||||
|   osPriorityNormal1       = 24+1,       ///< Priority: normal + 1
 | ||||
|   osPriorityNormal2       = 24+2,       ///< Priority: normal + 2
 | ||||
|   osPriorityNormal3       = 24+3,       ///< Priority: normal + 3
 | ||||
|   osPriorityNormal4       = 24+4,       ///< Priority: normal + 4
 | ||||
|   osPriorityNormal5       = 24+5,       ///< Priority: normal + 5
 | ||||
|   osPriorityNormal6       = 24+6,       ///< Priority: normal + 6
 | ||||
|   osPriorityNormal7       = 24+7,       ///< Priority: normal + 7
 | ||||
|   osPriorityAboveNormal   = 32,         ///< Priority: above normal
 | ||||
|   osPriorityAboveNormal1  = 32+1,       ///< Priority: above normal + 1
 | ||||
|   osPriorityAboveNormal2  = 32+2,       ///< Priority: above normal + 2
 | ||||
|   osPriorityAboveNormal3  = 32+3,       ///< Priority: above normal + 3
 | ||||
|   osPriorityAboveNormal4  = 32+4,       ///< Priority: above normal + 4
 | ||||
|   osPriorityAboveNormal5  = 32+5,       ///< Priority: above normal + 5
 | ||||
|   osPriorityAboveNormal6  = 32+6,       ///< Priority: above normal + 6
 | ||||
|   osPriorityAboveNormal7  = 32+7,       ///< Priority: above normal + 7
 | ||||
|   osPriorityHigh          = 40,         ///< Priority: high
 | ||||
|   osPriorityHigh1         = 40+1,       ///< Priority: high + 1
 | ||||
|   osPriorityHigh2         = 40+2,       ///< Priority: high + 2
 | ||||
|   osPriorityHigh3         = 40+3,       ///< Priority: high + 3
 | ||||
|   osPriorityHigh4         = 40+4,       ///< Priority: high + 4
 | ||||
|   osPriorityHigh5         = 40+5,       ///< Priority: high + 5
 | ||||
|   osPriorityHigh6         = 40+6,       ///< Priority: high + 6
 | ||||
|   osPriorityHigh7         = 40+7,       ///< Priority: high + 7
 | ||||
|   osPriorityRealtime      = 48,         ///< Priority: realtime
 | ||||
|   osPriorityRealtime1     = 48+1,       ///< Priority: realtime + 1
 | ||||
|   osPriorityRealtime2     = 48+2,       ///< Priority: realtime + 2
 | ||||
|   osPriorityRealtime3     = 48+3,       ///< Priority: realtime + 3
 | ||||
|   osPriorityRealtime4     = 48+4,       ///< Priority: realtime + 4
 | ||||
|   osPriorityRealtime5     = 48+5,       ///< Priority: realtime + 5
 | ||||
|   osPriorityRealtime6     = 48+6,       ///< Priority: realtime + 6
 | ||||
|   osPriorityRealtime7     = 48+7,       ///< Priority: realtime + 7
 | ||||
|   osPriorityISR           = 56,         ///< Reserved for ISR deferred thread.
 | ||||
|   osPriorityError         = -1,         ///< System cannot determine priority or illegal priority.
 | ||||
|   osPriorityReserved      = 0x7FFFFFFF  ///< Prevents enum down-size compiler optimization.
 | ||||
| } osPriority_t; | ||||
|   | ||||
| /// Entry point of a thread.
 | ||||
| typedef void (*osThreadFunc_t) (void *argument); | ||||
|   | ||||
| 
 | ||||
| /// Timer callback function.
 | ||||
| typedef void (*osTimerFunc_t) (void *argument); | ||||
|   | ||||
| 
 | ||||
| /// Timer type.
 | ||||
| typedef enum { | ||||
|   osTimerOnce               = 0,          ///< One-shot timer.
 | ||||
|   osTimerPeriodic           = 1           ///< Repeating timer.
 | ||||
| } osTimerType_t; | ||||
|   | ||||
| // Timeout value.
 | ||||
| #define osWaitForever         0xFFFFFFFFU ///< Wait forever timeout value.
 | ||||
|   | ||||
| // Flags options (\ref osThreadFlagsWait and \ref osEventFlagsWait).
 | ||||
| #define osFlagsWaitAny        0x00000000U ///< Wait for any flag (default).
 | ||||
| #define osFlagsWaitAll        0x00000001U ///< Wait for all flags.
 | ||||
| #define osFlagsNoClear        0x00000002U ///< Do not clear flags which have been specified to wait for.
 | ||||
|   | ||||
| // Flags errors (returned by osThreadFlagsXxxx and osEventFlagsXxxx).
 | ||||
| #define osFlagsError          0x80000000U ///< Error indicator.
 | ||||
| #define osFlagsErrorUnknown   0xFFFFFFFFU ///< osError (-1).
 | ||||
| #define osFlagsErrorTimeout   0xFFFFFFFEU ///< osErrorTimeout (-2).
 | ||||
| #define osFlagsErrorResource  0xFFFFFFFDU ///< osErrorResource (-3).
 | ||||
| #define osFlagsErrorParameter 0xFFFFFFFCU ///< osErrorParameter (-4).
 | ||||
| #define osFlagsErrorISR       0xFFFFFFFAU ///< osErrorISR (-6).
 | ||||
|   | ||||
| // Thread attributes (attr_bits in \ref osThreadAttr_t).
 | ||||
| #define osThreadDetached      0x00000000U ///< Thread created in detached mode (default)
 | ||||
| #define osThreadJoinable      0x00000001U ///< Thread created in joinable mode
 | ||||
|   | ||||
| // Mutex attributes (attr_bits in \ref osMutexAttr_t).
 | ||||
| #define osMutexRecursive      0x00000001U ///< Recursive mutex.
 | ||||
| #define osMutexPrioInherit    0x00000002U ///< Priority inherit protocol.
 | ||||
| #define osMutexRobust         0x00000008U ///< Robust mutex.
 | ||||
|   | ||||
| /// Status code values returned by CMSIS-RTOS functions.
 | ||||
| typedef enum { | ||||
|   osOK                      =  0,         ///< Operation completed successfully.
 | ||||
|   osError                   = -1,         ///< Unspecified RTOS error: run-time error but no other error message fits.
 | ||||
|   osErrorTimeout            = -2,         ///< Operation not completed within the timeout period.
 | ||||
|   osErrorResource           = -3,         ///< Resource not available.
 | ||||
|   osErrorParameter          = -4,         ///< Parameter error.
 | ||||
|   osErrorNoMemory           = -5,         ///< System is out of memory: it was impossible to allocate or reserve memory for the operation.
 | ||||
|   osErrorISR                = -6,         ///< Not allowed in ISR context: the function cannot be called from interrupt service routines.
 | ||||
|   osStatusReserved          = 0x7FFFFFFF  ///< Prevents enum down-size compiler optimization.
 | ||||
| } osStatus_t; | ||||
|   | ||||
|   | ||||
| /// \details Thread ID identifies the thread.
 | ||||
| typedef void *osThreadId_t; | ||||
|   | ||||
| 
 | ||||
| 
 | ||||
| /// \details Timer ID identifies the timer.
 | ||||
| typedef void *osTimerId_t; | ||||
|   | ||||
| /// \details Event Flags ID identifies the event flags.
 | ||||
| typedef void *osEventFlagsId_t; | ||||
|   | ||||
| /// \details Mutex ID identifies the mutex.
 | ||||
| typedef void *osMutexId_t; | ||||
|   | ||||
| /// \details Semaphore ID identifies the semaphore.
 | ||||
| typedef void *osSemaphoreId_t; | ||||
|   | ||||
| /// \details Memory Pool ID identifies the memory pool.
 | ||||
| typedef void *osMemoryPoolId_t; | ||||
|   | ||||
| 
 | ||||
| /// \details Message Queue ID identifies the message queue.
 | ||||
| typedef void *osMessageQueueId_t; | ||||
|   | ||||
|   | ||||
| 
 | ||||
| 
 | ||||
| #ifndef TZ_MODULEID_T | ||||
| #define TZ_MODULEID_T | ||||
| /// \details Data type that identifies secure software modules called by a process.
 | ||||
| typedef uint32_t TZ_ModuleId_t; | ||||
| #endif | ||||
|   | ||||
|   | ||||
| /// Attributes structure for thread.
 | ||||
| typedef struct { | ||||
|   const char                   *name;   ///< name of the thread
 | ||||
|   uint32_t                 attr_bits;   ///< attribute bits
 | ||||
|   void                      *cb_mem;    ///< memory for control block
 | ||||
|   uint32_t                   cb_size;   ///< size of provided memory for control block
 | ||||
|   void                   *stack_mem;    ///< memory for stack
 | ||||
|   uint32_t                stack_size;   ///< size of stack
 | ||||
|   osPriority_t              priority;   ///< initial thread priority (default: osPriorityNormal)
 | ||||
|   TZ_ModuleId_t            tz_module;   ///< TrustZone module identifier
 | ||||
|   uint32_t                  reserved;   ///< reserved (must be 0)
 | ||||
| } osThreadAttr_t; | ||||
|   | ||||
| 
 | ||||
| 
 | ||||
| /// Attributes structure for timer.
 | ||||
| typedef struct { | ||||
|   const char                   *name;   ///< name of the timer
 | ||||
| @ -256,41 +119,7 @@ typedef struct { | ||||
|   void                      *cb_mem;    ///< memory for control block
 | ||||
|   uint32_t                   cb_size;   ///< size of provided memory for control block
 | ||||
| } osTimerAttr_t; | ||||
|   | ||||
| /// Attributes structure for event flags.
 | ||||
| typedef struct { | ||||
|   const char                   *name;   ///< name of the event flags
 | ||||
|   uint32_t                 attr_bits;   ///< attribute bits
 | ||||
|   void                      *cb_mem;    ///< memory for control block
 | ||||
|   uint32_t                   cb_size;   ///< size of provided memory for control block
 | ||||
| } osEventFlagsAttr_t; | ||||
|   | ||||
| /// Attributes structure for mutex.
 | ||||
| typedef struct { | ||||
|   const char                   *name;   ///< name of the mutex
 | ||||
|   uint32_t                 attr_bits;   ///< attribute bits
 | ||||
|   void                      *cb_mem;    ///< memory for control block
 | ||||
|   uint32_t                   cb_size;   ///< size of provided memory for control block
 | ||||
| } osMutexAttr_t; | ||||
|   | ||||
| /// Attributes structure for semaphore.
 | ||||
| typedef struct { | ||||
|   const char                   *name;   ///< name of the semaphore
 | ||||
|   uint32_t                 attr_bits;   ///< attribute bits
 | ||||
|   void                      *cb_mem;    ///< memory for control block
 | ||||
|   uint32_t                   cb_size;   ///< size of provided memory for control block
 | ||||
| } osSemaphoreAttr_t; | ||||
|   | ||||
| /// Attributes structure for memory pool.
 | ||||
| typedef struct { | ||||
|   const char                   *name;   ///< name of the memory pool
 | ||||
|   uint32_t                 attr_bits;   ///< attribute bits
 | ||||
|   void                      *cb_mem;    ///< memory for control block
 | ||||
|   uint32_t                   cb_size;   ///< size of provided memory for control block
 | ||||
|   void                      *mp_mem;    ///< memory for data storage
 | ||||
|   uint32_t                   mp_size;   ///< size of provided memory for data storage 
 | ||||
| } osMemoryPoolAttr_t; | ||||
|   | ||||
| 
 | ||||
| /// Attributes structure for message queue.
 | ||||
| typedef struct { | ||||
|   const char                   *name;   ///< name of the message queue
 | ||||
| @ -298,196 +127,79 @@ typedef struct { | ||||
|   void                      *cb_mem;    ///< memory for control block
 | ||||
|   uint32_t                   cb_size;   ///< size of provided memory for control block
 | ||||
|   void                      *mq_mem;    ///< memory for data storage
 | ||||
|   uint32_t                   mq_size;   ///< size of provided memory for data storage 
 | ||||
|   uint32_t                   mq_size;   ///< size of provided memory for data storage
 | ||||
| } osMessageQueueAttr_t; | ||||
|   | ||||
|   | ||||
| 
 | ||||
| 
 | ||||
| //  ==== Kernel Management Functions ====
 | ||||
|   | ||||
| 
 | ||||
| /// Initialize the RTOS Kernel.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osKernelInitialize (void); | ||||
|   | ||||
| 
 | ||||
| ///  Get RTOS Kernel Information.
 | ||||
| /// \param[out]    version       pointer to buffer for retrieving version information.
 | ||||
| /// \param[out]    id_buf        pointer to buffer for retrieving kernel identification string.
 | ||||
| /// \param[in]     id_size       size of buffer for kernel identification string.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osKernelGetInfo (osVersion_t *version, char *id_buf, uint32_t id_size); | ||||
|   | ||||
| 
 | ||||
| /// Get the current RTOS Kernel state.
 | ||||
| /// \return current RTOS Kernel state.
 | ||||
| osKernelState_t osKernelGetState (void); | ||||
|   | ||||
| 
 | ||||
| /// Start the RTOS Kernel scheduler.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osKernelStart (void); | ||||
|   | ||||
| 
 | ||||
| /// Lock the RTOS Kernel scheduler.
 | ||||
| /// \return previous lock state (1 - locked, 0 - not locked, error code if negative).
 | ||||
| int32_t osKernelLock (void); | ||||
|   | ||||
| 
 | ||||
| /// Unlock the RTOS Kernel scheduler.
 | ||||
| /// \return previous lock state (1 - locked, 0 - not locked, error code if negative).
 | ||||
| int32_t osKernelUnlock (void); | ||||
|   | ||||
| 
 | ||||
| /// Restore the RTOS Kernel scheduler lock state.
 | ||||
| /// \param[in]     lock          lock state obtained by \ref osKernelLock or \ref osKernelUnlock.
 | ||||
| /// \return new lock state (1 - locked, 0 - not locked, error code if negative).
 | ||||
| int32_t osKernelRestoreLock (int32_t lock); | ||||
|   | ||||
| 
 | ||||
| /// Suspend the RTOS Kernel scheduler.
 | ||||
| /// \return time in ticks, for how long the system can sleep or power-down.
 | ||||
| uint32_t osKernelSuspend (void); | ||||
|   | ||||
| 
 | ||||
| /// Resume the RTOS Kernel scheduler.
 | ||||
| /// \param[in]     sleep_ticks   time in ticks for how long the system was in sleep or power-down mode.
 | ||||
| void osKernelResume (uint32_t sleep_ticks); | ||||
|   | ||||
| 
 | ||||
| /// Get the RTOS kernel tick count.
 | ||||
| /// \return RTOS kernel current tick count.
 | ||||
| uint32_t osKernelGetTickCount (void); | ||||
|   | ||||
| 
 | ||||
| /// Get the RTOS kernel tick frequency.
 | ||||
| /// \return frequency of the kernel tick in hertz, i.e. kernel ticks per second.
 | ||||
| uint32_t osKernelGetTickFreq (void); | ||||
|   | ||||
| /// Get the RTOS kernel system timer count.
 | ||||
| /// \return RTOS kernel current system timer count as 32-bit value.
 | ||||
| uint32_t osKernelGetSysTimerCount (void); | ||||
|   | ||||
| 
 | ||||
| /// Get the RTOS kernel system timer frequency.
 | ||||
| /// \return frequency of the system timer in hertz, i.e. timer ticks per second.
 | ||||
| uint32_t osKernelGetSysTimerFreq (void); | ||||
|   | ||||
|   | ||||
| //  ==== Thread Management Functions ====
 | ||||
|   | ||||
| /// Create a thread and add it to Active Threads.
 | ||||
| /// \param[in]     func          thread function.
 | ||||
| /// \param[in]     argument      pointer that is passed to the thread function as start argument.
 | ||||
| /// \param[in]     attr          thread attributes; NULL: default values.
 | ||||
| /// \return thread ID for reference by other functions or NULL in case of error.
 | ||||
| osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr); | ||||
|   | ||||
| /// Get name of a thread.
 | ||||
| /// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
 | ||||
| /// \return name as null-terminated string.
 | ||||
| const char *osThreadGetName (osThreadId_t thread_id); | ||||
|   | ||||
| /// Return the thread ID of the current running thread.
 | ||||
| /// \return thread ID for reference by other functions or NULL in case of error.
 | ||||
| osThreadId_t osThreadGetId (void); | ||||
|   | ||||
| /// Get current thread state of a thread.
 | ||||
| /// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
 | ||||
| /// \return current thread state of the specified thread.
 | ||||
| osThreadState_t osThreadGetState (osThreadId_t thread_id); | ||||
|   | ||||
| /// Get stack size of a thread.
 | ||||
| /// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
 | ||||
| /// \return stack size in bytes.
 | ||||
| uint32_t osThreadGetStackSize (osThreadId_t thread_id); | ||||
|   | ||||
| /// Get available stack space of a thread based on stack watermark recording during execution.
 | ||||
| /// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
 | ||||
| /// \return remaining stack space in bytes.
 | ||||
| uint32_t osThreadGetStackSpace (osThreadId_t thread_id); | ||||
|   | ||||
| /// Change priority of a thread.
 | ||||
| /// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
 | ||||
| /// \param[in]     priority      new priority value for the thread function.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osThreadSetPriority (osThreadId_t thread_id, osPriority_t priority); | ||||
|   | ||||
| /// Get current priority of a thread.
 | ||||
| /// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
 | ||||
| /// \return current priority value of the specified thread.
 | ||||
| osPriority_t osThreadGetPriority (osThreadId_t thread_id); | ||||
|   | ||||
| /// Pass control to next thread that is in state \b READY.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osThreadYield (void); | ||||
|   | ||||
| /// Suspend execution of a thread.
 | ||||
| /// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osThreadSuspend (osThreadId_t thread_id); | ||||
|   | ||||
| /// Resume execution of a thread.
 | ||||
| /// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osThreadResume (osThreadId_t thread_id); | ||||
|   | ||||
| /// Detach a thread (thread storage can be reclaimed when thread terminates).
 | ||||
| /// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osThreadDetach (osThreadId_t thread_id); | ||||
|   | ||||
| /// Wait for specified thread to terminate.
 | ||||
| /// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osThreadJoin (osThreadId_t thread_id); | ||||
|   | ||||
| /// Terminate execution of current running thread.
 | ||||
| __NO_RETURN void osThreadExit (void); | ||||
|   | ||||
| /// Terminate execution of a thread.
 | ||||
| /// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osThreadTerminate (osThreadId_t thread_id); | ||||
|   | ||||
| /// Get number of active threads.
 | ||||
| /// \return number of active threads.
 | ||||
| uint32_t osThreadGetCount (void); | ||||
|   | ||||
| /// Enumerate active threads.
 | ||||
| /// \param[out]    thread_array  pointer to array for retrieving thread IDs.
 | ||||
| /// \param[in]     array_items   maximum number of items in array for retrieving thread IDs.
 | ||||
| /// \return number of enumerated threads.
 | ||||
| uint32_t osThreadEnumerate (osThreadId_t *thread_array, uint32_t array_items); | ||||
|   | ||||
|   | ||||
| //  ==== Thread Flags Functions ====
 | ||||
|   | ||||
| /// Set the specified Thread Flags of a thread.
 | ||||
| /// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
 | ||||
| /// \param[in]     flags         specifies the flags of the thread that shall be set.
 | ||||
| /// \return thread flags after setting or error code if highest bit set.
 | ||||
| uint32_t osThreadFlagsSet (osThreadId_t thread_id, uint32_t flags); | ||||
|   | ||||
| /// Clear the specified Thread Flags of current running thread.
 | ||||
| /// \param[in]     flags         specifies the flags of the thread that shall be cleared.
 | ||||
| /// \return thread flags before clearing or error code if highest bit set.
 | ||||
| uint32_t osThreadFlagsClear (uint32_t flags); | ||||
|   | ||||
| /// Get the current Thread Flags of current running thread.
 | ||||
| /// \return current thread flags.
 | ||||
| uint32_t osThreadFlagsGet (void); | ||||
|   | ||||
| /// Wait for one or more Thread Flags of the current running thread to become signaled.
 | ||||
| /// \param[in]     flags         specifies the flags to wait for.
 | ||||
| /// \param[in]     options       specifies flags options (osFlagsXxxx).
 | ||||
| /// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
 | ||||
| /// \return thread flags before clearing or error code if highest bit set.
 | ||||
| uint32_t osThreadFlagsWait (uint32_t flags, uint32_t options, uint32_t timeout); | ||||
|   | ||||
|   | ||||
| 
 | ||||
| //  ==== Generic Wait Functions ====
 | ||||
|   | ||||
| 
 | ||||
| /// Wait for Timeout (Time Delay).
 | ||||
| /// \param[in]     ticks         \ref CMSIS_RTOS_TimeOutValue "time ticks" value
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osDelay (uint32_t ticks); | ||||
|   | ||||
| 
 | ||||
| /// Wait until specified time.
 | ||||
| /// \param[in]     ticks         absolute time in ticks
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osDelayUntil (uint32_t ticks); | ||||
|   | ||||
|   | ||||
| 
 | ||||
| 
 | ||||
| //  ==== Timer Management Functions ====
 | ||||
|   | ||||
| 
 | ||||
| /// Create and Initialize a timer.
 | ||||
| /// \param[in]     func          function pointer to callback function.
 | ||||
| /// \param[in]     type          \ref osTimerOnce for one-shot or \ref osTimerPeriodic for periodic behavior.
 | ||||
| @ -495,213 +207,47 @@ osStatus_t osDelayUntil (uint32_t ticks); | ||||
| /// \param[in]     attr          timer attributes; NULL: default values.
 | ||||
| /// \return timer ID for reference by other functions or NULL in case of error.
 | ||||
| osTimerId_t osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr); | ||||
|   | ||||
| 
 | ||||
| /// Get name of a timer.
 | ||||
| /// \param[in]     timer_id      timer ID obtained by \ref osTimerNew.
 | ||||
| /// \return name as null-terminated string.
 | ||||
| const char *osTimerGetName (osTimerId_t timer_id); | ||||
|   | ||||
| 
 | ||||
| /// Start or restart a timer.
 | ||||
| /// \param[in]     timer_id      timer ID obtained by \ref osTimerNew.
 | ||||
| /// \param[in]     ticks         \ref CMSIS_RTOS_TimeOutValue "time ticks" value of the timer.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osTimerStart (osTimerId_t timer_id, uint32_t ticks); | ||||
|   | ||||
| 
 | ||||
| /// Stop a timer.
 | ||||
| /// \param[in]     timer_id      timer ID obtained by \ref osTimerNew.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osTimerStop (osTimerId_t timer_id); | ||||
|   | ||||
| 
 | ||||
| /// Check if a timer is running.
 | ||||
| /// \param[in]     timer_id      timer ID obtained by \ref osTimerNew.
 | ||||
| /// \return 0 not running, 1 running.
 | ||||
| uint32_t osTimerIsRunning (osTimerId_t timer_id); | ||||
|   | ||||
| 
 | ||||
| /// Delete a timer.
 | ||||
| /// \param[in]     timer_id      timer ID obtained by \ref osTimerNew.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osTimerDelete (osTimerId_t timer_id); | ||||
|   | ||||
|   | ||||
| //  ==== Event Flags Management Functions ====
 | ||||
|   | ||||
| /// Create and Initialize an Event Flags object.
 | ||||
| /// \param[in]     attr          event flags attributes; NULL: default values.
 | ||||
| /// \return event flags ID for reference by other functions or NULL in case of error.
 | ||||
| osEventFlagsId_t osEventFlagsNew (const osEventFlagsAttr_t *attr); | ||||
|   | ||||
| /// Get name of an Event Flags object.
 | ||||
| /// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
 | ||||
| /// \return name as null-terminated string.
 | ||||
| const char *osEventFlagsGetName (osEventFlagsId_t ef_id); | ||||
|   | ||||
| /// Set the specified Event Flags.
 | ||||
| /// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
 | ||||
| /// \param[in]     flags         specifies the flags that shall be set.
 | ||||
| /// \return event flags after setting or error code if highest bit set.
 | ||||
| uint32_t osEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags); | ||||
|   | ||||
| /// Clear the specified Event Flags.
 | ||||
| /// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
 | ||||
| /// \param[in]     flags         specifies the flags that shall be cleared.
 | ||||
| /// \return event flags before clearing or error code if highest bit set.
 | ||||
| uint32_t osEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags); | ||||
|   | ||||
| /// Get the current Event Flags.
 | ||||
| /// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
 | ||||
| /// \return current event flags.
 | ||||
| uint32_t osEventFlagsGet (osEventFlagsId_t ef_id); | ||||
|   | ||||
| /// Wait for one or more Event Flags to become signaled.
 | ||||
| /// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
 | ||||
| /// \param[in]     flags         specifies the flags to wait for.
 | ||||
| /// \param[in]     options       specifies flags options (osFlagsXxxx).
 | ||||
| /// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
 | ||||
| /// \return event flags before clearing or error code if highest bit set.
 | ||||
| uint32_t osEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout); | ||||
|   | ||||
| /// Delete an Event Flags object.
 | ||||
| /// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osEventFlagsDelete (osEventFlagsId_t ef_id); | ||||
|   | ||||
|   | ||||
| //  ==== Mutex Management Functions ====
 | ||||
|   | ||||
| /// Create and Initialize a Mutex object.
 | ||||
| /// \param[in]     attr          mutex attributes; NULL: default values.
 | ||||
| /// \return mutex ID for reference by other functions or NULL in case of error.
 | ||||
| osMutexId_t osMutexNew (const osMutexAttr_t *attr); | ||||
|   | ||||
| /// Get name of a Mutex object.
 | ||||
| /// \param[in]     mutex_id      mutex ID obtained by \ref osMutexNew.
 | ||||
| /// \return name as null-terminated string.
 | ||||
| const char *osMutexGetName (osMutexId_t mutex_id); | ||||
|   | ||||
| /// Acquire a Mutex or timeout if it is locked.
 | ||||
| /// \param[in]     mutex_id      mutex ID obtained by \ref osMutexNew.
 | ||||
| /// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout); | ||||
|   | ||||
| /// Release a Mutex that was acquired by \ref osMutexAcquire.
 | ||||
| /// \param[in]     mutex_id      mutex ID obtained by \ref osMutexNew.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osMutexRelease (osMutexId_t mutex_id); | ||||
|   | ||||
| /// Get Thread which owns a Mutex object.
 | ||||
| /// \param[in]     mutex_id      mutex ID obtained by \ref osMutexNew.
 | ||||
| /// \return thread ID of owner thread or NULL when mutex was not acquired.
 | ||||
| osThreadId_t osMutexGetOwner (osMutexId_t mutex_id); | ||||
|   | ||||
| /// Delete a Mutex object.
 | ||||
| /// \param[in]     mutex_id      mutex ID obtained by \ref osMutexNew.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osMutexDelete (osMutexId_t mutex_id); | ||||
|   | ||||
|   | ||||
| //  ==== Semaphore Management Functions ====
 | ||||
|   | ||||
| /// Create and Initialize a Semaphore object.
 | ||||
| /// \param[in]     max_count     maximum number of available tokens.
 | ||||
| /// \param[in]     initial_count initial number of available tokens.
 | ||||
| /// \param[in]     attr          semaphore attributes; NULL: default values.
 | ||||
| /// \return semaphore ID for reference by other functions or NULL in case of error.
 | ||||
| osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr); | ||||
|   | ||||
| /// Get name of a Semaphore object.
 | ||||
| /// \param[in]     semaphore_id  semaphore ID obtained by \ref osSemaphoreNew.
 | ||||
| /// \return name as null-terminated string.
 | ||||
| const char *osSemaphoreGetName (osSemaphoreId_t semaphore_id); | ||||
|   | ||||
| /// Acquire a Semaphore token or timeout if no tokens are available.
 | ||||
| /// \param[in]     semaphore_id  semaphore ID obtained by \ref osSemaphoreNew.
 | ||||
| /// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout); | ||||
|   | ||||
| /// Release a Semaphore token up to the initial maximum count.
 | ||||
| /// \param[in]     semaphore_id  semaphore ID obtained by \ref osSemaphoreNew.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id); | ||||
|   | ||||
| /// Get current Semaphore token count.
 | ||||
| /// \param[in]     semaphore_id  semaphore ID obtained by \ref osSemaphoreNew.
 | ||||
| /// \return number of tokens available.
 | ||||
| uint32_t osSemaphoreGetCount (osSemaphoreId_t semaphore_id); | ||||
|   | ||||
| /// Delete a Semaphore object.
 | ||||
| /// \param[in]     semaphore_id  semaphore ID obtained by \ref osSemaphoreNew.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id); | ||||
|   | ||||
|   | ||||
| //  ==== Memory Pool Management Functions ====
 | ||||
|   | ||||
| /// Create and Initialize a Memory Pool object.
 | ||||
| /// \param[in]     block_count   maximum number of memory blocks in memory pool.
 | ||||
| /// \param[in]     block_size    memory block size in bytes.
 | ||||
| /// \param[in]     attr          memory pool attributes; NULL: default values.
 | ||||
| /// \return memory pool ID for reference by other functions or NULL in case of error.
 | ||||
| osMemoryPoolId_t osMemoryPoolNew (uint32_t block_count, uint32_t block_size, const osMemoryPoolAttr_t *attr); | ||||
|   | ||||
| /// Get name of a Memory Pool object.
 | ||||
| /// \param[in]     mp_id         memory pool ID obtained by \ref osMemoryPoolNew.
 | ||||
| /// \return name as null-terminated string.
 | ||||
| const char *osMemoryPoolGetName (osMemoryPoolId_t mp_id); | ||||
|   | ||||
| /// Allocate a memory block from a Memory Pool.
 | ||||
| /// \param[in]     mp_id         memory pool ID obtained by \ref osMemoryPoolNew.
 | ||||
| /// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
 | ||||
| /// \return address of the allocated memory block or NULL in case of no memory is available.
 | ||||
| void *osMemoryPoolAlloc (osMemoryPoolId_t mp_id, uint32_t timeout); | ||||
|   | ||||
| /// Return an allocated memory block back to a Memory Pool.
 | ||||
| /// \param[in]     mp_id         memory pool ID obtained by \ref osMemoryPoolNew.
 | ||||
| /// \param[in]     block         address of the allocated memory block to be returned to the memory pool.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osMemoryPoolFree (osMemoryPoolId_t mp_id, void *block); | ||||
|   | ||||
| /// Get maximum number of memory blocks in a Memory Pool.
 | ||||
| /// \param[in]     mp_id         memory pool ID obtained by \ref osMemoryPoolNew.
 | ||||
| /// \return maximum number of memory blocks.
 | ||||
| uint32_t osMemoryPoolGetCapacity (osMemoryPoolId_t mp_id); | ||||
|   | ||||
| /// Get memory block size in a Memory Pool.
 | ||||
| /// \param[in]     mp_id         memory pool ID obtained by \ref osMemoryPoolNew.
 | ||||
| /// \return memory block size in bytes.
 | ||||
| uint32_t osMemoryPoolGetBlockSize (osMemoryPoolId_t mp_id); | ||||
|   | ||||
| /// Get number of memory blocks used in a Memory Pool.
 | ||||
| /// \param[in]     mp_id         memory pool ID obtained by \ref osMemoryPoolNew.
 | ||||
| /// \return number of memory blocks used.
 | ||||
| uint32_t osMemoryPoolGetCount (osMemoryPoolId_t mp_id); | ||||
|   | ||||
| /// Get number of memory blocks available in a Memory Pool.
 | ||||
| /// \param[in]     mp_id         memory pool ID obtained by \ref osMemoryPoolNew.
 | ||||
| /// \return number of memory blocks available.
 | ||||
| uint32_t osMemoryPoolGetSpace (osMemoryPoolId_t mp_id); | ||||
|   | ||||
| /// Delete a Memory Pool object.
 | ||||
| /// \param[in]     mp_id         memory pool ID obtained by \ref osMemoryPoolNew.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osMemoryPoolDelete (osMemoryPoolId_t mp_id); | ||||
|   | ||||
|   | ||||
| 
 | ||||
| //  ==== Message Queue Management Functions ====
 | ||||
|   | ||||
| 
 | ||||
| /// Create and Initialize a Message Queue object.
 | ||||
| /// \param[in]     msg_count     maximum number of messages in queue.
 | ||||
| /// \param[in]     msg_size      maximum message size in bytes.
 | ||||
| /// \param[in]     attr          message queue attributes; NULL: default values.
 | ||||
| /// \return message queue ID for reference by other functions or NULL in case of error.
 | ||||
| osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr); | ||||
|   | ||||
| 
 | ||||
| /// Get name of a Message Queue object.
 | ||||
| /// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
 | ||||
| /// \return name as null-terminated string.
 | ||||
| const char *osMessageQueueGetName (osMessageQueueId_t mq_id); | ||||
|   | ||||
| 
 | ||||
| /// Put a Message into a Queue or timeout if Queue is full.
 | ||||
| /// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
 | ||||
| /// \param[in]     msg_ptr       pointer to buffer with message to put into a queue.
 | ||||
| @ -709,7 +255,7 @@ const char *osMessageQueueGetName (osMessageQueueId_t mq_id); | ||||
| /// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout); | ||||
|   | ||||
| 
 | ||||
| /// Get a Message from a Queue or timeout if Queue is empty.
 | ||||
| /// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
 | ||||
| /// \param[out]    msg_ptr       pointer to buffer for message to get from a queue.
 | ||||
| @ -717,40 +263,40 @@ osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uin | ||||
| /// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout); | ||||
|   | ||||
| 
 | ||||
| /// Get maximum number of messages in a Message Queue.
 | ||||
| /// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
 | ||||
| /// \return maximum number of messages.
 | ||||
| uint32_t osMessageQueueGetCapacity (osMessageQueueId_t mq_id); | ||||
|   | ||||
| 
 | ||||
| /// Get maximum message size in a Message Queue.
 | ||||
| /// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
 | ||||
| /// \return maximum message size in bytes.
 | ||||
| uint32_t osMessageQueueGetMsgSize (osMessageQueueId_t mq_id); | ||||
|   | ||||
| 
 | ||||
| /// Get number of queued messages in a Message Queue.
 | ||||
| /// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
 | ||||
| /// \return number of queued messages.
 | ||||
| uint32_t osMessageQueueGetCount (osMessageQueueId_t mq_id); | ||||
|   | ||||
| 
 | ||||
| /// Get number of available slots for messages in a Message Queue.
 | ||||
| /// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
 | ||||
| /// \return number of available slots for messages.
 | ||||
| uint32_t osMessageQueueGetSpace (osMessageQueueId_t mq_id); | ||||
|   | ||||
| 
 | ||||
| /// Reset a Message Queue to initial empty state.
 | ||||
| /// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osMessageQueueReset (osMessageQueueId_t mq_id); | ||||
|   | ||||
| 
 | ||||
| /// Delete a Message Queue object.
 | ||||
| /// \param[in]     mq_id         message queue ID obtained by \ref osMessageQueueNew.
 | ||||
| /// \return status code that indicates the execution status of the function.
 | ||||
| osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id); | ||||
|   | ||||
|   | ||||
| 
 | ||||
| 
 | ||||
| #ifdef  __cplusplus | ||||
| } | ||||
| #endif | ||||
|   | ||||
| 
 | ||||
| #endif  // CMSIS_OS2_H_
 | ||||
|  | ||||
| @ -1,63 +0,0 @@ | ||||
| /* --------------------------------------------------------------------------
 | ||||
|  * Copyright (c) 2013-2020 Arm Limited. All rights reserved. | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the License); you may | ||||
|  * not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an AS IS BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  *      Name:    freertos_mpool.h | ||||
|  *      Purpose: CMSIS RTOS2 wrapper for FreeRTOS | ||||
|  * | ||||
|  *---------------------------------------------------------------------------*/ | ||||
| 
 | ||||
| #ifndef FREERTOS_MPOOL_H_ | ||||
| #define FREERTOS_MPOOL_H_ | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include "FreeRTOS.h" | ||||
| #include "semphr.h" | ||||
| 
 | ||||
| /* Memory Pool implementation definitions */ | ||||
| #define MPOOL_STATUS              0x5EED0000U | ||||
| 
 | ||||
| /* Memory Block header */ | ||||
| typedef struct { | ||||
|   void *next;                   /* Pointer to next block  */ | ||||
| } MemPoolBlock_t; | ||||
| 
 | ||||
| /* Memory Pool control block */ | ||||
| typedef struct MemPoolDef_t { | ||||
|   MemPoolBlock_t    *head;      /* Pointer to head block   */ | ||||
|   SemaphoreHandle_t  sem;       /* Pool semaphore handle   */ | ||||
|   uint8_t           *mem_arr;   /* Pool memory array       */ | ||||
|   uint32_t           mem_sz;    /* Pool memory array size  */ | ||||
|   const char        *name;      /* Pointer to name string  */ | ||||
|   uint32_t           bl_sz;     /* Size of a single block  */ | ||||
|   uint32_t           bl_cnt;    /* Number of blocks        */ | ||||
|   uint32_t           n;         /* Block allocation index  */ | ||||
|   volatile uint32_t  status;    /* Object status flags     */ | ||||
| #if (configSUPPORT_STATIC_ALLOCATION == 1) | ||||
|   StaticSemaphore_t  mem_sem;   /* Semaphore object memory */ | ||||
| #endif | ||||
| } MemPool_t; | ||||
| 
 | ||||
| /* No need to hide static object type, just align to coding style */ | ||||
| #define StaticMemPool_t         MemPool_t | ||||
| 
 | ||||
| /* Define memory pool control block size */ | ||||
| #define MEMPOOL_CB_SIZE         (sizeof(StaticMemPool_t)) | ||||
| 
 | ||||
| /* Define size of the byte array required to create count of blocks of given size */ | ||||
| #define MEMPOOL_ARR_SIZE(bl_count, bl_size) (((((bl_size) + (4 - 1)) / 4) * 4)*(bl_count)) | ||||
| 
 | ||||
| #endif /* FREERTOS_MPOOL_H_ */ | ||||
| @ -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_ */ | ||||
|  | ||||
| @ -1,80 +0,0 @@ | ||||
| /**************************************************************************//**
 | ||||
|  * @file     os_tick.h | ||||
|  * @brief    CMSIS OS Tick header file | ||||
|  * @version  V1.0.2 | ||||
|  * @date     19. March 2021 | ||||
|  ******************************************************************************/ | ||||
| /*
 | ||||
|  * Copyright (c) 2017-2021 ARM Limited. All rights reserved. | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the License); you may | ||||
|  * not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an AS IS BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef OS_TICK_H | ||||
| #define OS_TICK_H | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #ifdef  __cplusplus | ||||
| extern "C" | ||||
| { | ||||
| #endif | ||||
| 
 | ||||
| /// IRQ Handler.
 | ||||
| #ifndef IRQHANDLER_T | ||||
| #define IRQHANDLER_T | ||||
| typedef void (*IRQHandler_t) (void); | ||||
| #endif | ||||
| 
 | ||||
| /// Setup OS Tick timer to generate periodic RTOS Kernel Ticks
 | ||||
| /// \param[in]     freq         tick frequency in Hz
 | ||||
| /// \param[in]     handler      tick IRQ handler
 | ||||
| /// \return 0 on success, -1 on error.
 | ||||
| int32_t  OS_Tick_Setup (uint32_t freq, IRQHandler_t handler); | ||||
| 
 | ||||
| /// Enable OS Tick timer interrupt
 | ||||
| void     OS_Tick_Enable (void); | ||||
| 
 | ||||
| /// Disable OS Tick timer interrupt
 | ||||
| void     OS_Tick_Disable (void); | ||||
| 
 | ||||
| /// Acknowledge execution of OS Tick timer interrupt
 | ||||
| void     OS_Tick_AcknowledgeIRQ (void); | ||||
| 
 | ||||
| /// Get OS Tick timer IRQ number
 | ||||
| /// \return OS Tick IRQ number
 | ||||
| int32_t  OS_Tick_GetIRQn (void); | ||||
| 
 | ||||
| /// Get OS Tick timer clock frequency
 | ||||
| /// \return OS Tick timer clock frequency in Hz
 | ||||
| uint32_t OS_Tick_GetClock (void); | ||||
| 
 | ||||
| /// Get OS Tick timer interval reload value
 | ||||
| /// \return OS Tick timer interval reload value
 | ||||
| uint32_t OS_Tick_GetInterval (void); | ||||
| 
 | ||||
| /// Get OS Tick timer counter value
 | ||||
| /// \return OS Tick timer counter value
 | ||||
| uint32_t OS_Tick_GetCount (void); | ||||
| 
 | ||||
| /// Get OS Tick timer overflow status
 | ||||
| /// \return OS Tick overflow status (1 - overflow, 0 - no overflow).
 | ||||
| uint32_t OS_Tick_GetOverflow (void); | ||||
| 
 | ||||
| #ifdef  __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif  /* OS_TICK_H */ | ||||
| @ -3,49 +3,58 @@ | ||||
| #include <furi.h> | ||||
| #include <furi_hal_spi.h> | ||||
| 
 | ||||
| static const osThreadAttr_t platform_irq_thread_attr = { | ||||
|     .name = "RfalIrqDriver", | ||||
|     .stack_size = 1024, | ||||
|     .priority = osPriorityRealtime, | ||||
| }; | ||||
| typedef struct { | ||||
|     FuriThread* thread; | ||||
|     volatile PlatformIrqCallback callback; | ||||
| } RfalPlatform; | ||||
| 
 | ||||
| static volatile osThreadId_t platform_irq_thread_id = NULL; | ||||
| static volatile PlatformIrqCallback platform_irq_callback = NULL; | ||||
| static const GpioPin pin = {ST25R_INT_PORT, ST25R_INT_PIN}; | ||||
| static volatile RfalPlatform rfal_platform = { | ||||
|     .thread = NULL, | ||||
|     .callback = NULL, | ||||
| }; | ||||
| 
 | ||||
| void nfc_isr(void* _ctx) { | ||||
|     UNUSED(_ctx); | ||||
|     if(platform_irq_callback && platformGpioIsHigh(ST25R_INT_PORT, ST25R_INT_PIN)) { | ||||
|         osThreadFlagsSet(platform_irq_thread_id, 0x1); | ||||
|     if(rfal_platform.callback && platformGpioIsHigh(ST25R_INT_PORT, ST25R_INT_PIN)) { | ||||
|         furi_thread_flags_set(furi_thread_get_id(rfal_platform.thread), 0x1); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void platformIrqThread() { | ||||
| int32_t rfal_platform_irq_thread(void* context) { | ||||
|     UNUSED(context); | ||||
| 
 | ||||
|     while(1) { | ||||
|         uint32_t flags = osThreadFlagsWait(0x1, osFlagsWaitAny, osWaitForever); | ||||
|         uint32_t flags = furi_thread_flags_wait(0x1, osFlagsWaitAny, osWaitForever); | ||||
|         if(flags & 0x1) { | ||||
|             platform_irq_callback(); | ||||
|             rfal_platform.callback(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void platformEnableIrqCallback() { | ||||
|     furi_hal_gpio_init(&pin, GpioModeInterruptRise, GpioPullDown, GpioSpeedLow); | ||||
|     furi_hal_gpio_enable_int_callback(&pin); | ||||
|     furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeInterruptRise, GpioPullDown, GpioSpeedLow); | ||||
|     furi_hal_gpio_enable_int_callback(&gpio_nfc_irq_rfid_pull); | ||||
| } | ||||
| 
 | ||||
| void platformDisableIrqCallback() { | ||||
|     furi_hal_gpio_init(&pin, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); | ||||
|     furi_hal_gpio_disable_int_callback(&pin); | ||||
|     furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); | ||||
|     furi_hal_gpio_disable_int_callback(&gpio_nfc_irq_rfid_pull); | ||||
| } | ||||
| 
 | ||||
| void platformSetIrqCallback(PlatformIrqCallback callback) { | ||||
|     platform_irq_callback = callback; | ||||
|     platform_irq_thread_id = osThreadNew(platformIrqThread, NULL, &platform_irq_thread_attr); | ||||
|     furi_hal_gpio_add_int_callback(&pin, nfc_isr, NULL); | ||||
|     rfal_platform.callback = callback; | ||||
|     rfal_platform.thread = furi_thread_alloc(); | ||||
| 
 | ||||
|     furi_thread_set_name(rfal_platform.thread, "RfalIrqDriver"); | ||||
|     furi_thread_set_callback(rfal_platform.thread, rfal_platform_irq_thread); | ||||
|     furi_thread_set_stack_size(rfal_platform.thread, 1024); | ||||
|     furi_thread_set_priority(rfal_platform.thread, FuriThreadPriorityIsr); | ||||
|     furi_thread_start(rfal_platform.thread); | ||||
| 
 | ||||
|     furi_hal_gpio_add_int_callback(&gpio_nfc_irq_rfid_pull, nfc_isr, NULL); | ||||
|     // Disable interrupt callback as the pin is shared between 2 apps
 | ||||
|     // It is enabled in rfalLowPowerModeStop()
 | ||||
|     furi_hal_gpio_disable_int_callback(&pin); | ||||
|     furi_hal_gpio_disable_int_callback(&gpio_nfc_irq_rfid_pull); | ||||
| } | ||||
| 
 | ||||
| bool platformSpiTxRx(const uint8_t* txBuf, uint8_t* rxBuf, uint16_t len) { | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 あく
						あく