diff --git a/applications/services/bt/bt_service/bt.c b/applications/services/bt/bt_service/bt.c index d72e745ee32..2eeeab2868b 100644 --- a/applications/services/bt/bt_service/bt.c +++ b/applications/services/bt/bt_service/bt.c @@ -430,13 +430,11 @@ static void bt_change_profile(Bt* bt, BtMessage* message) { *message->profile_instance = NULL; } } - if(message->lock) api_lock_unlock(message->lock); } -static void bt_close_connection(Bt* bt, BtMessage* message) { +static void bt_close_connection(Bt* bt) { bt_close_rpc_connection(bt); furi_hal_bt_stop_advertising(); - if(message->lock) api_lock_unlock(message->lock); } static void bt_apply_settings(Bt* bt) { @@ -484,19 +482,13 @@ static void bt_load_settings(Bt* bt) { } static void bt_handle_get_settings(Bt* bt, BtMessage* message) { - furi_assert(message->lock); *message->data.settings = bt->bt_settings; - api_lock_unlock(message->lock); } static void bt_handle_set_settings(Bt* bt, BtMessage* message) { - furi_assert(message->lock); bt->bt_settings = *message->data.csettings; - bt_apply_settings(bt); bt_settings_save(&bt->bt_settings); - - api_lock_unlock(message->lock); } static void bt_handle_reload_keys_settings(Bt* bt) { @@ -548,6 +540,12 @@ int32_t bt_srv(void* p) { while(1) { furi_check( furi_message_queue_get(bt->message_queue, &message, FuriWaitForever) == FuriStatusOk); + FURI_LOG_D( + TAG, + "call %d, lock 0x%p, result 0x%p", + message.type, + (void*)message.lock, + (void*)message.result); if(message.type == BtMessageTypeUpdateStatus) { // Update view ports bt_statusbar_update(bt); @@ -571,7 +569,7 @@ int32_t bt_srv(void* p) { } else if(message.type == BtMessageTypeSetProfile) { bt_change_profile(bt, &message); } else if(message.type == BtMessageTypeDisconnect) { - bt_close_connection(bt, &message); + bt_close_connection(bt); } else if(message.type == BtMessageTypeForgetBondedDevices) { bt_keys_storage_delete(bt->keys_storage); } else if(message.type == BtMessageTypeGetSettings) { @@ -581,6 +579,8 @@ int32_t bt_srv(void* p) { } else if(message.type == BtMessageTypeReloadKeysSettings) { bt_handle_reload_keys_settings(bt); } + + if(message.lock) api_lock_unlock(message.lock); } return 0; diff --git a/applications/services/dialogs/dialogs_module_file_browser.c b/applications/services/dialogs/dialogs_module_file_browser.c index 12a7439e609..603c27cff82 100644 --- a/applications/services/dialogs/dialogs_module_file_browser.c +++ b/applications/services/dialogs/dialogs_module_file_browser.c @@ -54,11 +54,14 @@ bool dialogs_app_process_module_file_browser(const DialogsAppMessageDataFileBrow ret = file_browser_context->result; view_holder_set_view(view_holder, NULL); - view_holder_free(view_holder); file_browser_stop(file_browser); + file_browser_free(file_browser); + view_holder_free(view_holder); + api_lock_free(file_browser_context->lock); free(file_browser_context); + furi_record_close(RECORD_GUI); return ret; diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index 08a2c3f6ded..41d55841ef0 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -67,7 +67,7 @@ static RpcSystemCallbacks rpc_systems[] = { struct RpcSession { Rpc* rpc; - FuriThreadId thread_id; + FuriThread* thread; RpcHandlerDict_t handlers; FuriStreamBuffer* stream; @@ -172,7 +172,7 @@ size_t rpc_session_feed( size_t bytes_sent = furi_stream_buffer_send(session->stream, encoded_bytes, size, timeout); - furi_thread_flags_set(session->thread_id, RpcEvtNewData); + furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtNewData); return bytes_sent; } @@ -220,7 +220,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 */ - furi_thread_flags_set(session->thread_id, RpcEvtDisconnect); + furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtDisconnect); } } else if(flags & RpcEvtNewData) { // Just wake thread up @@ -347,32 +347,37 @@ static int32_t rpc_session_worker(void* context) { return 0; } -static void rpc_session_thread_release_callback( - FuriThread* thread, - FuriThreadState thread_state, - void* context) { - if(thread_state == FuriThreadStateStopped) { - RpcSession* session = (RpcSession*)context; +static void rpc_session_thread_pending_callback(void* context, uint32_t arg) { + UNUSED(arg); + RpcSession* session = (RpcSession*)context; - for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) { - if(rpc_systems[i].free) { - (rpc_systems[i].free)(session->system_contexts[i]); - } - } - free(session->system_contexts); - free(session->decoded_message); - RpcHandlerDict_clear(session->handlers); - furi_stream_buffer_free(session->stream); - - furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever); - if(session->terminated_callback) { - session->terminated_callback(session->context); + for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) { + if(rpc_systems[i].free) { + (rpc_systems[i].free)(session->system_contexts[i]); } - furi_mutex_release(session->callbacks_mutex); + } + free(session->system_contexts); + free(session->decoded_message); + RpcHandlerDict_clear(session->handlers); + furi_stream_buffer_free(session->stream); + + furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever); + if(session->terminated_callback) { + session->terminated_callback(session->context); + } + furi_mutex_release(session->callbacks_mutex); + + furi_mutex_free(session->callbacks_mutex); + furi_thread_join(session->thread); + furi_thread_free(session->thread); + free(session); +} - furi_mutex_free(session->callbacks_mutex); - furi_thread_free(thread); - free(session); +static void + rpc_session_thread_state_callback(FuriThread* thread, FuriThreadState state, void* context) { + UNUSED(thread); + if(state == FuriThreadStateStopped) { + furi_timer_pending_callback(rpc_session_thread_pending_callback, context, 0); } } @@ -404,14 +409,12 @@ RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner) { }; rpc_add_handler(session, PB_Main_stop_session_tag, &rpc_handler); - FuriThread* thread = - furi_thread_alloc_ex("RpcSessionWorker", 3072, rpc_session_worker, session); - session->thread_id = furi_thread_get_id(thread); + session->thread = furi_thread_alloc_ex("RpcSessionWorker", 3072, rpc_session_worker, session); - furi_thread_set_state_context(thread, session); - furi_thread_set_state_callback(thread, rpc_session_thread_release_callback); + furi_thread_set_state_context(session->thread, session); + furi_thread_set_state_callback(session->thread, rpc_session_thread_state_callback); - furi_thread_start(thread); + furi_thread_start(session->thread); return session; } @@ -423,7 +426,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); - furi_thread_flags_set(session->thread_id, RpcEvtDisconnect); + furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtDisconnect); } void rpc_on_system_start(void* p) { diff --git a/furi/core/kernel.c b/furi/core/kernel.c index f3f84e692e4..34c562bb34e 100644 --- a/furi/core/kernel.c +++ b/furi/core/kernel.c @@ -33,7 +33,7 @@ bool furi_kernel_is_irq_or_masked(void) { } bool furi_kernel_is_running(void) { - return xTaskGetSchedulerState() != taskSCHEDULER_RUNNING; + return xTaskGetSchedulerState() == taskSCHEDULER_RUNNING; } int32_t furi_kernel_lock(void) { @@ -129,6 +129,8 @@ uint32_t furi_kernel_get_tick_frequency(void) { void furi_delay_tick(uint32_t ticks) { furi_check(!furi_kernel_is_irq_or_masked()); + furi_check(furi_thread_get_current_id() != xTaskGetIdleTaskHandle()); + if(ticks == 0U) { taskYIELD(); } else { @@ -138,6 +140,7 @@ void furi_delay_tick(uint32_t ticks) { FuriStatus furi_delay_until_tick(uint32_t tick) { furi_check(!furi_kernel_is_irq_or_masked()); + furi_check(furi_thread_get_current_id() != xTaskGetIdleTaskHandle()); TickType_t tcnt, delay; FuriStatus stat; diff --git a/furi/core/log.c b/furi/core/log.c index f8110b46ac7..fb0c9671136 100644 --- a/furi/core/log.c +++ b/furi/core/log.c @@ -108,10 +108,17 @@ void furi_log_puts(const char* data) { } void furi_log_print_format(FuriLogLevel level, const char* tag, const char* format, ...) { - if(level <= furi_log.log_level && - furi_mutex_acquire(furi_log.mutex, FuriWaitForever) == FuriStatusOk) { - FuriString* string; - string = furi_string_alloc(); + do { + if(level > furi_log.log_level) { + break; + } + + if(furi_mutex_acquire(furi_log.mutex, furi_kernel_is_running() ? FuriWaitForever : 0) != + FuriStatusOk) { + break; + } + + FuriString* string = furi_string_alloc(); const char* color = _FURI_LOG_CLR_RESET; const char* log_letter = " "; @@ -157,7 +164,7 @@ void furi_log_print_format(FuriLogLevel level, const char* tag, const char* form furi_log_puts("\r\n"); furi_mutex_release(furi_log.mutex); - } + } while(0); } void furi_log_print_raw_format(FuriLogLevel level, const char* format, ...) { diff --git a/furi/core/thread.c b/furi/core/thread.c index 3990dd63d25..fd576ea72bb 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -1,6 +1,7 @@ -#include "thread.h" +#include "thread_i.h" #include "thread_list_i.h" #include "kernel.h" +#include "message_queue.h" #include "memmgr.h" #include "memmgr_heap.h" #include "check.h" @@ -67,6 +68,8 @@ static_assert(offsetof(FuriThread, container) == 0); // Our idle priority should be equal to the one from FreeRTOS static_assert(FuriThreadPriorityIdle == tskIDLE_PRIORITY); +static FuriMessageQueue* furi_thread_scrub_message_queue = NULL; + static size_t __furi_thread_stdout_write(FuriThread* thread, const char* data, size_t size); static int32_t __furi_thread_stdout_flush(FuriThread* thread); @@ -125,7 +128,9 @@ static void furi_thread_body(void* context) { furi_thread_set_state(thread, FuriThreadStateStopping); - vTaskDelete(NULL); + furi_message_queue_put(furi_thread_scrub_message_queue, &thread, FuriWaitForever); + + vTaskSuspend(NULL); furi_thread_catch(); } @@ -159,6 +164,31 @@ static void furi_thread_init_common(FuriThread* thread) { } } +void furi_thread_init(void) { + furi_thread_scrub_message_queue = furi_message_queue_alloc(8, sizeof(FuriThread*)); +} + +void furi_thread_scrub(void) { + FuriThread* thread_to_scrub = NULL; + while(true) { + furi_check( + furi_message_queue_get( + furi_thread_scrub_message_queue, &thread_to_scrub, FuriWaitForever) == + FuriStatusOk); + + TaskHandle_t task = (TaskHandle_t)thread_to_scrub; + + // Delete task: FreeRTOS will remove task from all lists where it may be + vTaskDelete(task); + // Sanity check: ensure that local storage is ours and clear it + furi_check(pvTaskGetThreadLocalStoragePointer(task, 0) == thread_to_scrub); + vTaskSetThreadLocalStoragePointer(task, 0, NULL); + + // Deliver thread stopped callback + furi_thread_set_state(thread_to_scrub, FuriThreadStateStopped); + } +} + FuriThread* furi_thread_alloc(void) { FuriThread* thread = malloc(sizeof(FuriThread)); @@ -358,16 +388,6 @@ void furi_thread_start(FuriThread* thread) { &thread->container) == (TaskHandle_t)thread); } -void furi_thread_cleanup_tcb_event(TaskHandle_t task) { - FuriThread* thread = pvTaskGetThreadLocalStoragePointer(task, 0); - if(thread) { - // clear thread local storage - vTaskSetThreadLocalStoragePointer(task, 0, NULL); - furi_check(thread == (FuriThread*)task); - furi_thread_set_state(thread, FuriThreadStateStopped); - } -} - bool furi_thread_join(FuriThread* thread) { furi_check(thread); // Cannot join a service thread diff --git a/furi/core/thread.h b/furi/core/thread.h index c320fdbc10d..ed7aa4553b0 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -21,10 +21,10 @@ extern "C" { * Many of the FuriThread functions MUST ONLY be called when the thread is STOPPED. */ typedef enum { - FuriThreadStateStopped, /**< Thread is stopped and is safe to release */ - FuriThreadStateStopping, /**< Thread is stopping */ - FuriThreadStateStarting, /**< Thread is starting */ - FuriThreadStateRunning, /**< Thread is running */ + FuriThreadStateStopped, /**< Thread is stopped and is safe to release. Event delivered from system init thread(TCB cleanup routine). It is safe to release thread instance. */ + FuriThreadStateStopping, /**< Thread is stopping. Event delivered from child thread. */ + FuriThreadStateStarting, /**< Thread is starting. Event delivered from parent(self) thread. */ + FuriThreadStateRunning, /**< Thread is running. Event delivered from child thread. */ } FuriThreadState; /** @@ -32,6 +32,7 @@ typedef enum { */ typedef enum { FuriThreadPriorityIdle = 0, /**< Idle priority */ + FuriThreadPriorityInit = 4, /**< Init System Thread Priority */ FuriThreadPriorityLowest = 14, /**< Lowest */ FuriThreadPriorityLow = 15, /**< Low */ FuriThreadPriorityNormal = 16, /**< Normal, system default */ @@ -77,13 +78,15 @@ typedef int32_t (*FuriThreadCallback)(void* context); typedef void (*FuriThreadStdoutWriteCallback)(const char* data, size_t size); /** - * @brief State change callback function pointer type. + * @brief State change callback function pointer type. * - * The function to be used as a state callback MUST follow this signature. + * The function to be used as a state callback MUST follow this + * signature. * - * @param[in] pointer to the FuriThread instance that changed the state - * @param[in] state identifier of the state the thread has transitioned to - * @param[in,out] context pointer to a user-specified object + * @param[in] thread to the FuriThread instance that changed the state + * @param[in] state identifier of the state the thread has transitioned + * to + * @param[in,out] context pointer to a user-specified object */ typedef void (*FuriThreadStateCallback)(FuriThread* thread, FuriThreadState state, void* context); diff --git a/furi/core/thread_i.h b/furi/core/thread_i.h new file mode 100644 index 00000000000..c6b12a78027 --- /dev/null +++ b/furi/core/thread_i.h @@ -0,0 +1,7 @@ +#pragma once + +#include "thread.h" + +void furi_thread_init(void); + +void furi_thread_scrub(void); diff --git a/furi/core/timer.c b/furi/core/timer.c index 01adbeb89e8..ddd82e33194 100644 --- a/furi/core/timer.c +++ b/furi/core/timer.c @@ -17,12 +17,24 @@ static_assert(offsetof(FuriTimer, container) == 0); #define TIMER_DELETED_EVENT (1U << 0) -static void TimerCallback(TimerHandle_t hTimer) { +static void furi_timer_callback(TimerHandle_t hTimer) { FuriTimer* instance = pvTimerGetTimerID(hTimer); furi_check(instance); instance->cb_func(instance->cb_context); } +static void furi_timer_flush_epilogue(void* context, uint32_t arg) { + furi_assert(context); + UNUSED(arg); + + EventGroupHandle_t hEvent = context; + + // See https://github.com/FreeRTOS/FreeRTOS-Kernel/issues/1142 + vTaskSuspendAll(); + xEventGroupSetBits(hEvent, TIMER_DELETED_EVENT); + (void)xTaskResumeAll(); +} + FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* context) { furi_check((furi_kernel_is_irq_or_masked() == 0U) && (func != NULL)); @@ -33,23 +45,13 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co const UBaseType_t reload = (type == FuriTimerTypeOnce ? pdFALSE : pdTRUE); const TimerHandle_t hTimer = xTimerCreateStatic( - NULL, portMAX_DELAY, reload, instance, TimerCallback, &instance->container); + NULL, portMAX_DELAY, reload, instance, furi_timer_callback, &instance->container); furi_check(hTimer == (TimerHandle_t)instance); return instance; } -static void furi_timer_epilogue(void* context, uint32_t arg) { - furi_assert(context); - UNUSED(arg); - - EventGroupHandle_t hEvent = context; - vTaskSuspendAll(); - xEventGroupSetBits(hEvent, TIMER_DELETED_EVENT); - (void)xTaskResumeAll(); -} - void furi_timer_free(FuriTimer* instance) { furi_check(!furi_kernel_is_irq_or_masked()); furi_check(instance); @@ -57,16 +59,21 @@ void furi_timer_free(FuriTimer* instance) { TimerHandle_t hTimer = (TimerHandle_t)instance; furi_check(xTimerDelete(hTimer, portMAX_DELAY) == pdPASS); + furi_timer_flush(); + + free(instance); +} + +void furi_timer_flush(void) { StaticEventGroup_t event_container = {}; EventGroupHandle_t hEvent = xEventGroupCreateStatic(&event_container); - furi_check(xTimerPendFunctionCall(furi_timer_epilogue, hEvent, 0, portMAX_DELAY) == pdPASS); + furi_check( + xTimerPendFunctionCall(furi_timer_flush_epilogue, hEvent, 0, portMAX_DELAY) == pdPASS); furi_check( xEventGroupWaitBits(hEvent, TIMER_DELETED_EVENT, pdFALSE, pdTRUE, portMAX_DELAY) == TIMER_DELETED_EVENT); vEventGroupDelete(hEvent); - - free(instance); } FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks) { @@ -112,6 +119,8 @@ FuriStatus furi_timer_stop(FuriTimer* instance) { furi_check(xTimerStop(hTimer, portMAX_DELAY) == pdPASS); + furi_timer_flush(); + return FuriStatusOk; } diff --git a/furi/core/timer.h b/furi/core/timer.h index 00056db18eb..9d8df3dc620 100644 --- a/furi/core/timer.h +++ b/furi/core/timer.h @@ -35,6 +35,12 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co */ void furi_timer_free(FuriTimer* instance); +/** Flush timer task control message queue + * + * Ensures that all commands before this point was processed. + */ +void furi_timer_flush(void); + /** Start timer * * @warning This is asynchronous call, real operation will happen as soon as @@ -61,8 +67,7 @@ FuriStatus furi_timer_restart(FuriTimer* instance, uint32_t ticks); /** Stop timer * - * @warning This is asynchronous call, real operation will happen as soon as - * timer service process this request. + * @warning This is synchronous call that will be blocked till timer queue processed. * * @param instance The pointer to FuriTimer instance * diff --git a/furi/furi.c b/furi/furi.c index f4e64ee099b..bc7452f130e 100644 --- a/furi/furi.c +++ b/furi/furi.c @@ -1,5 +1,7 @@ #include "furi.h" +#include "core/thread_i.h" + #include #include @@ -7,6 +9,7 @@ void furi_init(void) { furi_check(!furi_kernel_is_irq_or_masked()); furi_check(xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED); + furi_thread_init(); furi_log_init(); furi_record_init(); } @@ -18,3 +21,7 @@ void furi_run(void) { /* Start the kernel scheduler */ vTaskStartScheduler(); } + +void furi_background(void) { + furi_thread_scrub(); +} diff --git a/furi/furi.h b/furi/furi.h index d75debe9876..6ddf2857757 100644 --- a/furi/furi.h +++ b/furi/furi.h @@ -35,6 +35,8 @@ void furi_init(void); void furi_run(void); +void furi_background(void); + #ifdef __cplusplus } #endif diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 7e612de8620..2b04e3e4039 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,76.0,, +Version,+,77.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/cli/cli.h,, @@ -1102,6 +1102,7 @@ Function,-,ftello,off_t,FILE* Function,-,ftrylockfile,int,FILE* Function,-,funlockfile,void,FILE* Function,-,funopen,FILE*,"const void*, int (*)(void*, char*, int), int (*)(void*, const char*, int), fpos_t (*)(void*, fpos_t, int), int (*)(void*)" +Function,-,furi_background,void, Function,+,furi_delay_ms,void,uint32_t Function,+,furi_delay_tick,void,uint32_t Function,+,furi_delay_until_tick,FuriStatus,uint32_t @@ -1672,6 +1673,7 @@ Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" Function,+,furi_thread_suspend,void,FuriThreadId Function,+,furi_thread_yield,void, Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" +Function,+,furi_timer_flush,void, Function,+,furi_timer_free,void,FuriTimer* Function,+,furi_timer_get_expire_time,uint32_t,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer* diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 02e184a8a20..71d9213d85d 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,76.0,, +Version,+,77.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -1207,6 +1207,7 @@ Function,-,ftello,off_t,FILE* Function,-,ftrylockfile,int,FILE* Function,-,funlockfile,void,FILE* Function,-,funopen,FILE*,"const void*, int (*)(void*, char*, int), int (*)(void*, const char*, int), fpos_t (*)(void*, fpos_t, int), int (*)(void*)" +Function,-,furi_background,void, Function,+,furi_delay_ms,void,uint32_t Function,+,furi_delay_tick,void,uint32_t Function,+,furi_delay_until_tick,FuriStatus,uint32_t @@ -1886,6 +1887,7 @@ Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" Function,+,furi_thread_suspend,void,FuriThreadId Function,+,furi_thread_yield,void, Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" +Function,+,furi_timer_flush,void, Function,+,furi_timer_free,void,FuriTimer* Function,+,furi_timer_get_expire_time,uint32_t,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer* diff --git a/targets/f7/ble_glue/ble_glue.c b/targets/f7/ble_glue/ble_glue.c index 73bb41badc8..fe101b2c931 100644 --- a/targets/f7/ble_glue/ble_glue.c +++ b/targets/f7/ble_glue/ble_glue.c @@ -87,6 +87,8 @@ void ble_glue_init(void) { TL_Init(); ble_glue->shci_mtx = furi_mutex_alloc(FuriMutexTypeNormal); + // Take mutex, SHCI will release it in most unusual way later + furi_check(furi_mutex_acquire(ble_glue->shci_mtx, FuriWaitForever) == FuriStatusOk); // FreeRTOS system task creation ble_event_thread_start(); @@ -248,7 +250,9 @@ void ble_glue_stop(void) { ble_event_thread_stop(); // Free resources furi_mutex_free(ble_glue->shci_mtx); + ble_glue->shci_mtx = NULL; furi_timer_free(ble_glue->hardfault_check_timer); + ble_glue->hardfault_check_timer = NULL; ble_glue_clear_shared_memory(); free(ble_glue); @@ -309,10 +313,13 @@ BleGlueCommandResult ble_glue_force_c2_mode(BleGlueC2Mode desired_mode) { static void ble_sys_status_not_callback(SHCI_TL_CmdStatus_t status) { switch(status) { case SHCI_TL_CmdBusy: - furi_mutex_acquire(ble_glue->shci_mtx, FuriWaitForever); + furi_check( + furi_mutex_acquire( + ble_glue->shci_mtx, furi_kernel_is_running() ? FuriWaitForever : 0) == + FuriStatusOk); break; case SHCI_TL_CmdAvailable: - furi_mutex_release(ble_glue->shci_mtx); + furi_check(furi_mutex_release(ble_glue->shci_mtx) == FuriStatusOk); break; default: break; diff --git a/targets/f7/ble_glue/gap.c b/targets/f7/ble_glue/gap.c index 9cd33456b41..732440ccf90 100644 --- a/targets/f7/ble_glue/gap.c +++ b/targets/f7/ble_glue/gap.c @@ -129,7 +129,7 @@ BleEventFlowStatus ble_event_app_notification(void* pckt) { event_pckt = (hci_event_pckt*)((hci_uart_pckt*)pckt)->data; furi_check(gap); - furi_mutex_acquire(gap->state_mutex, FuriWaitForever); + furi_check(furi_mutex_acquire(gap->state_mutex, FuriWaitForever) == FuriStatusOk); switch(event_pckt->evt) { case HCI_DISCONNECTION_COMPLETE_EVT_CODE: { @@ -304,7 +304,7 @@ BleEventFlowStatus ble_event_app_notification(void* pckt) { break; } - furi_mutex_release(gap->state_mutex); + furi_check(furi_mutex_release(gap->state_mutex) == FuriStatusOk); return BleEventFlowEnable; } @@ -490,7 +490,7 @@ static void gap_advertise_stop(void) { } void gap_start_advertising(void) { - furi_mutex_acquire(gap->state_mutex, FuriWaitForever); + furi_check(furi_mutex_acquire(gap->state_mutex, FuriWaitForever) == FuriStatusOk); if(gap->state == GapStateIdle) { gap->state = GapStateStartingAdv; FURI_LOG_I(TAG, "Start advertising"); @@ -498,18 +498,18 @@ void gap_start_advertising(void) { GapCommand command = GapCommandAdvFast; furi_check(furi_message_queue_put(gap->command_queue, &command, 0) == FuriStatusOk); } - furi_mutex_release(gap->state_mutex); + furi_check(furi_mutex_release(gap->state_mutex) == FuriStatusOk); } void gap_stop_advertising(void) { - furi_mutex_acquire(gap->state_mutex, FuriWaitForever); + furi_check(furi_mutex_acquire(gap->state_mutex, FuriWaitForever) == FuriStatusOk); if(gap->state > GapStateIdle) { FURI_LOG_I(TAG, "Stop advertising"); gap->enable_adv = false; GapCommand command = GapCommandAdvStop; furi_check(furi_message_queue_put(gap->command_queue, &command, 0) == FuriStatusOk); } - furi_mutex_release(gap->state_mutex); + furi_check(furi_mutex_release(gap->state_mutex) == FuriStatusOk); } static void gap_advetise_timer_callback(void* context) { @@ -566,9 +566,9 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) { GapState gap_get_state(void) { GapState state; if(gap) { - furi_mutex_acquire(gap->state_mutex, FuriWaitForever); + furi_check(furi_mutex_acquire(gap->state_mutex, FuriWaitForever) == FuriStatusOk); state = gap->state; - furi_mutex_release(gap->state_mutex); + furi_check(furi_mutex_release(gap->state_mutex) == FuriStatusOk); } else { state = GapStateUninitialized; } @@ -577,17 +577,21 @@ GapState gap_get_state(void) { void gap_thread_stop(void) { if(gap) { - furi_mutex_acquire(gap->state_mutex, FuriWaitForever); + furi_check(furi_mutex_acquire(gap->state_mutex, FuriWaitForever) == FuriStatusOk); gap->enable_adv = false; GapCommand command = GapCommandKillThread; furi_message_queue_put(gap->command_queue, &command, FuriWaitForever); - furi_mutex_release(gap->state_mutex); + furi_check(furi_mutex_release(gap->state_mutex) == FuriStatusOk); furi_thread_join(gap->thread); furi_thread_free(gap->thread); + gap->thread = NULL; // Free resources furi_mutex_free(gap->state_mutex); + gap->state_mutex = NULL; furi_message_queue_free(gap->command_queue); + gap->command_queue = NULL; furi_timer_free(gap->advertise_timer); + gap->advertise_timer = NULL; ble_event_dispatcher_reset(); free(gap); @@ -604,7 +608,7 @@ static int32_t gap_app(void* context) { FURI_LOG_E(TAG, "Message queue get error: %d", status); continue; } - furi_mutex_acquire(gap->state_mutex, FuriWaitForever); + furi_check(furi_mutex_acquire(gap->state_mutex, FuriWaitForever) == FuriStatusOk); if(command == GapCommandKillThread) { break; } @@ -615,7 +619,7 @@ static int32_t gap_app(void* context) { } else if(command == GapCommandAdvStop) { gap_advertise_stop(); } - furi_mutex_release(gap->state_mutex); + furi_check(furi_mutex_release(gap->state_mutex) == FuriStatusOk); } return 0; diff --git a/targets/f7/furi_hal/furi_hal_spi.c b/targets/f7/furi_hal/furi_hal_spi.c index 49bcd48a1ef..2a7cb7c25f4 100644 --- a/targets/f7/furi_hal/furi_hal_spi.c +++ b/targets/f7/furi_hal/furi_hal_spi.c @@ -202,7 +202,7 @@ bool furi_hal_spi_bus_trx_dma( furi_check(size > 0); // If scheduler is not running, use blocking mode - if(furi_kernel_is_running()) { + if(!furi_kernel_is_running()) { return furi_hal_spi_bus_trx(handle, tx_buffer, rx_buffer, size, timeout_ms); } diff --git a/targets/f7/inc/FreeRTOSConfig.h b/targets/f7/inc/FreeRTOSConfig.h index 82cda2c6da7..357019ea233 100644 --- a/targets/f7/inc/FreeRTOSConfig.h +++ b/targets/f7/inc/FreeRTOSConfig.h @@ -84,6 +84,7 @@ to exclude the API function. */ #define INCLUDE_xTaskGetCurrentTaskHandle 1 #define INCLUDE_xTaskGetSchedulerState 1 #define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskGetIdleTaskHandle 1 /* Workaround for various notification issues: * - First one used by system primitives @@ -129,25 +130,11 @@ See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ #define configMAX_SYSCALL_INTERRUPT_PRIORITY \ (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) -/* Normal assert() semantics without relying on the provision of an assert.h -header file. */ -#ifdef DEBUG -#include -#define configASSERT(x) \ - if((x) == 0) { \ - furi_crash("FreeRTOS Assert"); \ - } -#endif - /* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS standard names. */ #define vPortSVCHandler SVC_Handler #define xPortPendSVHandler PendSV_Handler -#define USE_CUSTOM_SYSTICK_HANDLER_IMPLEMENTATION 1 -#define configOVERRIDE_DEFAULT_TICK_CONFIGURATION \ - 1 /* required only for Keil but does not hurt otherwise */ - #define traceTASK_SWITCHED_IN() \ extern void furi_hal_mpu_set_stack_protection(uint32_t* stack); \ furi_hal_mpu_set_stack_protection((uint32_t*)pxCurrentTCB->pxStack); \ @@ -157,6 +144,14 @@ standard names. */ // referencing `FreeRTOS_errno' here vvvvv because FreeRTOS calls our hook _before_ copying the value into the TCB, hence a manual write to the TCB would get overwritten #define traceTASK_SWITCHED_OUT() FreeRTOS_errno = errno -#define portCLEAN_UP_TCB(pxTCB) \ - extern void furi_thread_cleanup_tcb_event(TaskHandle_t task); \ - furi_thread_cleanup_tcb_event(pxTCB) +/* Normal assert() semantics without relying on the provision of an assert.h +header file. */ +#ifdef DEBUG +#define configASSERT(x) \ + if((x) == 0) { \ + furi_crash("FreeRTOS Assert"); \ + } +#endif + +// Must be last line of config because of recursion +#include diff --git a/targets/f7/src/main.c b/targets/f7/src/main.c index 77961f0eff8..21775f19a24 100644 --- a/targets/f7/src/main.c +++ b/targets/f7/src/main.c @@ -15,6 +15,8 @@ int32_t init_task(void* context) { // Init flipper flipper_init(); + furi_background(); + return 0; } @@ -25,7 +27,8 @@ int main(void) { // Flipper critical FURI HAL furi_hal_init_early(); - FuriThread* main_thread = furi_thread_alloc_ex("Init", 4096, init_task, NULL); + FuriThread* main_thread = furi_thread_alloc_ex("InitSrv", 1024, init_task, NULL); + furi_thread_set_priority(main_thread, FuriThreadPriorityInit); #ifdef FURI_RAM_EXEC // Prevent entering sleep mode when executed from RAM