[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:
あく 2022-06-20 17:54:48 +03:00 committed by GitHub
parent 7618c8ba6f
commit 839e52ac32
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
61 changed files with 1467 additions and 2784 deletions

View file

@ -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) {

View file

@ -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);
}

View file

@ -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) {

View file

@ -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);

View file

@ -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) {

View file

@ -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);
}
}

View file

@ -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

View file

@ -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);
}

View file

@ -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);
}
}

View file

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

View file

@ -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(

View file

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

View file

@ -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) {

View file

@ -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

View file

@ -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;
}

View file

@ -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);

View file

@ -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));
*/
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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;

View file

@ -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) {

View file

@ -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);

View file

@ -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
View 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

View file

@ -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 {

View file

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

222
core/furi/event_flags.c Normal file
View 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
View 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

View file

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

View file

@ -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 = "";
}

View file

@ -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
View 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
View 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

View file

@ -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;

View file

@ -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
View 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
View 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

View file

@ -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;

View file

@ -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);
}

View file

@ -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

View file

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

View file

@ -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

View file

@ -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

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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();
}
}

View file

@ -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);

View file

@ -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 */

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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) {

View file

@ -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

View file

@ -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_

View file

@ -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_ */

View file

@ -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_ */

View file

@ -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 */

View file

@ -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) {

View file

@ -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);

View file

@ -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) {