mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 04:34:43 +04:00
Furi: A Lot of Fixes (#3942)
- BT Service: cleanup code - Dialog: correct release order in file browser - Rpc: rollback to pre #3881 state - Kernel: fix inverted behavior in furi_kernel_is_running - Log: properly take mutex when kernel is not running - Thread: rework tread control block scrubbing procedure, ensure that we don't do stupid things in idle task, add new priority for init task - Timer: add control queue flush method, force flush on stop - Furi: system init task now performs thread scrubbing - BleGlue: add some extra checks - FreeRTOSConfig: fix bunch of issues that were preventing configuration from being properly applied and cleanup
This commit is contained in:
@@ -430,13 +430,11 @@ static void bt_change_profile(Bt* bt, BtMessage* message) {
|
|||||||
*message->profile_instance = NULL;
|
*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);
|
bt_close_rpc_connection(bt);
|
||||||
furi_hal_bt_stop_advertising();
|
furi_hal_bt_stop_advertising();
|
||||||
if(message->lock) api_lock_unlock(message->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bt_apply_settings(Bt* bt) {
|
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) {
|
static void bt_handle_get_settings(Bt* bt, BtMessage* message) {
|
||||||
furi_assert(message->lock);
|
|
||||||
*message->data.settings = bt->bt_settings;
|
*message->data.settings = bt->bt_settings;
|
||||||
api_lock_unlock(message->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bt_handle_set_settings(Bt* bt, BtMessage* message) {
|
static void bt_handle_set_settings(Bt* bt, BtMessage* message) {
|
||||||
furi_assert(message->lock);
|
|
||||||
bt->bt_settings = *message->data.csettings;
|
bt->bt_settings = *message->data.csettings;
|
||||||
|
|
||||||
bt_apply_settings(bt);
|
bt_apply_settings(bt);
|
||||||
bt_settings_save(&bt->bt_settings);
|
bt_settings_save(&bt->bt_settings);
|
||||||
|
|
||||||
api_lock_unlock(message->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bt_handle_reload_keys_settings(Bt* bt) {
|
static void bt_handle_reload_keys_settings(Bt* bt) {
|
||||||
@@ -548,6 +540,12 @@ int32_t bt_srv(void* p) {
|
|||||||
while(1) {
|
while(1) {
|
||||||
furi_check(
|
furi_check(
|
||||||
furi_message_queue_get(bt->message_queue, &message, FuriWaitForever) == FuriStatusOk);
|
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) {
|
if(message.type == BtMessageTypeUpdateStatus) {
|
||||||
// Update view ports
|
// Update view ports
|
||||||
bt_statusbar_update(bt);
|
bt_statusbar_update(bt);
|
||||||
@@ -571,7 +569,7 @@ int32_t bt_srv(void* p) {
|
|||||||
} else if(message.type == BtMessageTypeSetProfile) {
|
} else if(message.type == BtMessageTypeSetProfile) {
|
||||||
bt_change_profile(bt, &message);
|
bt_change_profile(bt, &message);
|
||||||
} else if(message.type == BtMessageTypeDisconnect) {
|
} else if(message.type == BtMessageTypeDisconnect) {
|
||||||
bt_close_connection(bt, &message);
|
bt_close_connection(bt);
|
||||||
} else if(message.type == BtMessageTypeForgetBondedDevices) {
|
} else if(message.type == BtMessageTypeForgetBondedDevices) {
|
||||||
bt_keys_storage_delete(bt->keys_storage);
|
bt_keys_storage_delete(bt->keys_storage);
|
||||||
} else if(message.type == BtMessageTypeGetSettings) {
|
} else if(message.type == BtMessageTypeGetSettings) {
|
||||||
@@ -581,6 +579,8 @@ int32_t bt_srv(void* p) {
|
|||||||
} else if(message.type == BtMessageTypeReloadKeysSettings) {
|
} else if(message.type == BtMessageTypeReloadKeysSettings) {
|
||||||
bt_handle_reload_keys_settings(bt);
|
bt_handle_reload_keys_settings(bt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(message.lock) api_lock_unlock(message.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -54,11 +54,14 @@ bool dialogs_app_process_module_file_browser(const DialogsAppMessageDataFileBrow
|
|||||||
ret = file_browser_context->result;
|
ret = file_browser_context->result;
|
||||||
|
|
||||||
view_holder_set_view(view_holder, NULL);
|
view_holder_set_view(view_holder, NULL);
|
||||||
view_holder_free(view_holder);
|
|
||||||
file_browser_stop(file_browser);
|
file_browser_stop(file_browser);
|
||||||
|
|
||||||
file_browser_free(file_browser);
|
file_browser_free(file_browser);
|
||||||
|
view_holder_free(view_holder);
|
||||||
|
|
||||||
api_lock_free(file_browser_context->lock);
|
api_lock_free(file_browser_context->lock);
|
||||||
free(file_browser_context);
|
free(file_browser_context);
|
||||||
|
|
||||||
furi_record_close(RECORD_GUI);
|
furi_record_close(RECORD_GUI);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ static RpcSystemCallbacks rpc_systems[] = {
|
|||||||
struct RpcSession {
|
struct RpcSession {
|
||||||
Rpc* rpc;
|
Rpc* rpc;
|
||||||
|
|
||||||
FuriThreadId thread_id;
|
FuriThread* thread;
|
||||||
|
|
||||||
RpcHandlerDict_t handlers;
|
RpcHandlerDict_t handlers;
|
||||||
FuriStreamBuffer* stream;
|
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);
|
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;
|
return bytes_sent;
|
||||||
}
|
}
|
||||||
@@ -220,7 +220,7 @@ bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) {
|
|||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
/* Save disconnect flag and continue reading buffer */
|
/* 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) {
|
} else if(flags & RpcEvtNewData) {
|
||||||
// Just wake thread up
|
// Just wake thread up
|
||||||
@@ -347,32 +347,37 @@ static int32_t rpc_session_worker(void* context) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rpc_session_thread_release_callback(
|
static void rpc_session_thread_pending_callback(void* context, uint32_t arg) {
|
||||||
FuriThread* thread,
|
UNUSED(arg);
|
||||||
FuriThreadState thread_state,
|
RpcSession* session = (RpcSession*)context;
|
||||||
void* context) {
|
|
||||||
if(thread_state == FuriThreadStateStopped) {
|
|
||||||
RpcSession* session = (RpcSession*)context;
|
|
||||||
|
|
||||||
for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) {
|
for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) {
|
||||||
if(rpc_systems[i].free) {
|
if(rpc_systems[i].free) {
|
||||||
(rpc_systems[i].free)(session->system_contexts[i]);
|
(rpc_systems[i].free)(session->system_contexts[i]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
free(session->system_contexts);
|
}
|
||||||
free(session->decoded_message);
|
free(session->system_contexts);
|
||||||
RpcHandlerDict_clear(session->handlers);
|
free(session->decoded_message);
|
||||||
furi_stream_buffer_free(session->stream);
|
RpcHandlerDict_clear(session->handlers);
|
||||||
|
furi_stream_buffer_free(session->stream);
|
||||||
|
|
||||||
furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever);
|
furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever);
|
||||||
if(session->terminated_callback) {
|
if(session->terminated_callback) {
|
||||||
session->terminated_callback(session->context);
|
session->terminated_callback(session->context);
|
||||||
}
|
}
|
||||||
furi_mutex_release(session->callbacks_mutex);
|
furi_mutex_release(session->callbacks_mutex);
|
||||||
|
|
||||||
furi_mutex_free(session->callbacks_mutex);
|
furi_mutex_free(session->callbacks_mutex);
|
||||||
furi_thread_free(thread);
|
furi_thread_join(session->thread);
|
||||||
free(session);
|
furi_thread_free(session->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);
|
rpc_add_handler(session, PB_Main_stop_session_tag, &rpc_handler);
|
||||||
|
|
||||||
FuriThread* thread =
|
session->thread = furi_thread_alloc_ex("RpcSessionWorker", 3072, rpc_session_worker, session);
|
||||||
furi_thread_alloc_ex("RpcSessionWorker", 3072, rpc_session_worker, session);
|
|
||||||
session->thread_id = furi_thread_get_id(thread);
|
|
||||||
|
|
||||||
furi_thread_set_state_context(thread, session);
|
furi_thread_set_state_context(session->thread, session);
|
||||||
furi_thread_set_state_callback(thread, rpc_session_thread_release_callback);
|
furi_thread_set_state_callback(session->thread, rpc_session_thread_state_callback);
|
||||||
|
|
||||||
furi_thread_start(thread);
|
furi_thread_start(session->thread);
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
@@ -423,7 +426,7 @@ void rpc_session_close(RpcSession* session) {
|
|||||||
rpc_session_set_send_bytes_callback(session, NULL);
|
rpc_session_set_send_bytes_callback(session, NULL);
|
||||||
rpc_session_set_close_callback(session, NULL);
|
rpc_session_set_close_callback(session, NULL);
|
||||||
rpc_session_set_buffer_is_empty_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) {
|
void rpc_on_system_start(void* p) {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ bool furi_kernel_is_irq_or_masked(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool furi_kernel_is_running(void) {
|
bool furi_kernel_is_running(void) {
|
||||||
return xTaskGetSchedulerState() != taskSCHEDULER_RUNNING;
|
return xTaskGetSchedulerState() == taskSCHEDULER_RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t furi_kernel_lock(void) {
|
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) {
|
void furi_delay_tick(uint32_t ticks) {
|
||||||
furi_check(!furi_kernel_is_irq_or_masked());
|
furi_check(!furi_kernel_is_irq_or_masked());
|
||||||
|
furi_check(furi_thread_get_current_id() != xTaskGetIdleTaskHandle());
|
||||||
|
|
||||||
if(ticks == 0U) {
|
if(ticks == 0U) {
|
||||||
taskYIELD();
|
taskYIELD();
|
||||||
} else {
|
} else {
|
||||||
@@ -138,6 +140,7 @@ void furi_delay_tick(uint32_t ticks) {
|
|||||||
|
|
||||||
FuriStatus furi_delay_until_tick(uint32_t tick) {
|
FuriStatus furi_delay_until_tick(uint32_t tick) {
|
||||||
furi_check(!furi_kernel_is_irq_or_masked());
|
furi_check(!furi_kernel_is_irq_or_masked());
|
||||||
|
furi_check(furi_thread_get_current_id() != xTaskGetIdleTaskHandle());
|
||||||
|
|
||||||
TickType_t tcnt, delay;
|
TickType_t tcnt, delay;
|
||||||
FuriStatus stat;
|
FuriStatus stat;
|
||||||
|
|||||||
@@ -108,10 +108,17 @@ void furi_log_puts(const char* data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void furi_log_print_format(FuriLogLevel level, const char* tag, const char* format, ...) {
|
void furi_log_print_format(FuriLogLevel level, const char* tag, const char* format, ...) {
|
||||||
if(level <= furi_log.log_level &&
|
do {
|
||||||
furi_mutex_acquire(furi_log.mutex, FuriWaitForever) == FuriStatusOk) {
|
if(level > furi_log.log_level) {
|
||||||
FuriString* string;
|
break;
|
||||||
string = furi_string_alloc();
|
}
|
||||||
|
|
||||||
|
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* color = _FURI_LOG_CLR_RESET;
|
||||||
const char* log_letter = " ";
|
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_log_puts("\r\n");
|
||||||
|
|
||||||
furi_mutex_release(furi_log.mutex);
|
furi_mutex_release(furi_log.mutex);
|
||||||
}
|
} while(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void furi_log_print_raw_format(FuriLogLevel level, const char* format, ...) {
|
void furi_log_print_raw_format(FuriLogLevel level, const char* format, ...) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "thread.h"
|
#include "thread_i.h"
|
||||||
#include "thread_list_i.h"
|
#include "thread_list_i.h"
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
|
#include "message_queue.h"
|
||||||
#include "memmgr.h"
|
#include "memmgr.h"
|
||||||
#include "memmgr_heap.h"
|
#include "memmgr_heap.h"
|
||||||
#include "check.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
|
// Our idle priority should be equal to the one from FreeRTOS
|
||||||
static_assert(FuriThreadPriorityIdle == tskIDLE_PRIORITY);
|
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 size_t __furi_thread_stdout_write(FuriThread* thread, const char* data, size_t size);
|
||||||
static int32_t __furi_thread_stdout_flush(FuriThread* thread);
|
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);
|
furi_thread_set_state(thread, FuriThreadStateStopping);
|
||||||
|
|
||||||
vTaskDelete(NULL);
|
furi_message_queue_put(furi_thread_scrub_message_queue, &thread, FuriWaitForever);
|
||||||
|
|
||||||
|
vTaskSuspend(NULL);
|
||||||
furi_thread_catch();
|
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* furi_thread_alloc(void) {
|
||||||
FuriThread* thread = malloc(sizeof(FuriThread));
|
FuriThread* thread = malloc(sizeof(FuriThread));
|
||||||
|
|
||||||
@@ -358,16 +388,6 @@ void furi_thread_start(FuriThread* thread) {
|
|||||||
&thread->container) == (TaskHandle_t)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) {
|
bool furi_thread_join(FuriThread* thread) {
|
||||||
furi_check(thread);
|
furi_check(thread);
|
||||||
// Cannot join a service thread
|
// Cannot join a service thread
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ extern "C" {
|
|||||||
* Many of the FuriThread functions MUST ONLY be called when the thread is STOPPED.
|
* Many of the FuriThread functions MUST ONLY be called when the thread is STOPPED.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FuriThreadStateStopped, /**< Thread is stopped and is safe to release */
|
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 */
|
FuriThreadStateStopping, /**< Thread is stopping. Event delivered from child thread. */
|
||||||
FuriThreadStateStarting, /**< Thread is starting */
|
FuriThreadStateStarting, /**< Thread is starting. Event delivered from parent(self) thread. */
|
||||||
FuriThreadStateRunning, /**< Thread is running */
|
FuriThreadStateRunning, /**< Thread is running. Event delivered from child thread. */
|
||||||
} FuriThreadState;
|
} FuriThreadState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,6 +32,7 @@ typedef enum {
|
|||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FuriThreadPriorityIdle = 0, /**< Idle priority */
|
FuriThreadPriorityIdle = 0, /**< Idle priority */
|
||||||
|
FuriThreadPriorityInit = 4, /**< Init System Thread Priority */
|
||||||
FuriThreadPriorityLowest = 14, /**< Lowest */
|
FuriThreadPriorityLowest = 14, /**< Lowest */
|
||||||
FuriThreadPriorityLow = 15, /**< Low */
|
FuriThreadPriorityLow = 15, /**< Low */
|
||||||
FuriThreadPriorityNormal = 16, /**< Normal, system default */
|
FuriThreadPriorityNormal = 16, /**< Normal, system default */
|
||||||
@@ -77,13 +78,15 @@ typedef int32_t (*FuriThreadCallback)(void* context);
|
|||||||
typedef void (*FuriThreadStdoutWriteCallback)(const char* data, size_t size);
|
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] thread to the FuriThread instance that changed the state
|
||||||
* @param[in] state identifier of the state the thread has transitioned to
|
* @param[in] state identifier of the state the thread has transitioned
|
||||||
* @param[in,out] context pointer to a user-specified object
|
* to
|
||||||
|
* @param[in,out] context pointer to a user-specified object
|
||||||
*/
|
*/
|
||||||
typedef void (*FuriThreadStateCallback)(FuriThread* thread, FuriThreadState state, void* context);
|
typedef void (*FuriThreadStateCallback)(FuriThread* thread, FuriThreadState state, void* context);
|
||||||
|
|
||||||
|
|||||||
7
furi/core/thread_i.h
Normal file
7
furi/core/thread_i.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
|
void furi_thread_init(void);
|
||||||
|
|
||||||
|
void furi_thread_scrub(void);
|
||||||
@@ -17,12 +17,24 @@ static_assert(offsetof(FuriTimer, container) == 0);
|
|||||||
|
|
||||||
#define TIMER_DELETED_EVENT (1U << 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);
|
FuriTimer* instance = pvTimerGetTimerID(hTimer);
|
||||||
furi_check(instance);
|
furi_check(instance);
|
||||||
instance->cb_func(instance->cb_context);
|
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) {
|
FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* context) {
|
||||||
furi_check((furi_kernel_is_irq_or_masked() == 0U) && (func != NULL));
|
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 UBaseType_t reload = (type == FuriTimerTypeOnce ? pdFALSE : pdTRUE);
|
||||||
const TimerHandle_t hTimer = xTimerCreateStatic(
|
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);
|
furi_check(hTimer == (TimerHandle_t)instance);
|
||||||
|
|
||||||
return 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) {
|
void furi_timer_free(FuriTimer* instance) {
|
||||||
furi_check(!furi_kernel_is_irq_or_masked());
|
furi_check(!furi_kernel_is_irq_or_masked());
|
||||||
furi_check(instance);
|
furi_check(instance);
|
||||||
@@ -57,16 +59,21 @@ void furi_timer_free(FuriTimer* instance) {
|
|||||||
TimerHandle_t hTimer = (TimerHandle_t)instance;
|
TimerHandle_t hTimer = (TimerHandle_t)instance;
|
||||||
furi_check(xTimerDelete(hTimer, portMAX_DELAY) == pdPASS);
|
furi_check(xTimerDelete(hTimer, portMAX_DELAY) == pdPASS);
|
||||||
|
|
||||||
|
furi_timer_flush();
|
||||||
|
|
||||||
|
free(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void furi_timer_flush(void) {
|
||||||
StaticEventGroup_t event_container = {};
|
StaticEventGroup_t event_container = {};
|
||||||
EventGroupHandle_t hEvent = xEventGroupCreateStatic(&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(
|
furi_check(
|
||||||
xEventGroupWaitBits(hEvent, TIMER_DELETED_EVENT, pdFALSE, pdTRUE, portMAX_DELAY) ==
|
xEventGroupWaitBits(hEvent, TIMER_DELETED_EVENT, pdFALSE, pdTRUE, portMAX_DELAY) ==
|
||||||
TIMER_DELETED_EVENT);
|
TIMER_DELETED_EVENT);
|
||||||
vEventGroupDelete(hEvent);
|
vEventGroupDelete(hEvent);
|
||||||
|
|
||||||
free(instance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks) {
|
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_check(xTimerStop(hTimer, portMAX_DELAY) == pdPASS);
|
||||||
|
|
||||||
|
furi_timer_flush();
|
||||||
|
|
||||||
return FuriStatusOk;
|
return FuriStatusOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,12 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co
|
|||||||
*/
|
*/
|
||||||
void furi_timer_free(FuriTimer* instance);
|
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
|
/** Start timer
|
||||||
*
|
*
|
||||||
* @warning This is asynchronous call, real operation will happen as soon as
|
* @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
|
/** Stop timer
|
||||||
*
|
*
|
||||||
* @warning This is asynchronous call, real operation will happen as soon as
|
* @warning This is synchronous call that will be blocked till timer queue processed.
|
||||||
* timer service process this request.
|
|
||||||
*
|
*
|
||||||
* @param instance The pointer to FuriTimer instance
|
* @param instance The pointer to FuriTimer instance
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "furi.h"
|
#include "furi.h"
|
||||||
|
|
||||||
|
#include "core/thread_i.h"
|
||||||
|
|
||||||
#include <FreeRTOS.h>
|
#include <FreeRTOS.h>
|
||||||
#include <queue.h>
|
#include <queue.h>
|
||||||
|
|
||||||
@@ -7,6 +9,7 @@ void furi_init(void) {
|
|||||||
furi_check(!furi_kernel_is_irq_or_masked());
|
furi_check(!furi_kernel_is_irq_or_masked());
|
||||||
furi_check(xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED);
|
furi_check(xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED);
|
||||||
|
|
||||||
|
furi_thread_init();
|
||||||
furi_log_init();
|
furi_log_init();
|
||||||
furi_record_init();
|
furi_record_init();
|
||||||
}
|
}
|
||||||
@@ -18,3 +21,7 @@ void furi_run(void) {
|
|||||||
/* Start the kernel scheduler */
|
/* Start the kernel scheduler */
|
||||||
vTaskStartScheduler();
|
vTaskStartScheduler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void furi_background(void) {
|
||||||
|
furi_thread_scrub();
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ void furi_init(void);
|
|||||||
|
|
||||||
void furi_run(void);
|
void furi_run(void);
|
||||||
|
|
||||||
|
void furi_background(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
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.h,,
|
||||||
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
||||||
Header,+,applications/services/cli/cli.h,,
|
Header,+,applications/services/cli/cli.h,,
|
||||||
@@ -1102,6 +1102,7 @@ Function,-,ftello,off_t,FILE*
|
|||||||
Function,-,ftrylockfile,int,FILE*
|
Function,-,ftrylockfile,int,FILE*
|
||||||
Function,-,funlockfile,void,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,-,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_ms,void,uint32_t
|
||||||
Function,+,furi_delay_tick,void,uint32_t
|
Function,+,furi_delay_tick,void,uint32_t
|
||||||
Function,+,furi_delay_until_tick,FuriStatus,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_suspend,void,FuriThreadId
|
||||||
Function,+,furi_thread_yield,void,
|
Function,+,furi_thread_yield,void,
|
||||||
Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*"
|
Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*"
|
||||||
|
Function,+,furi_timer_flush,void,
|
||||||
Function,+,furi_timer_free,void,FuriTimer*
|
Function,+,furi_timer_free,void,FuriTimer*
|
||||||
Function,+,furi_timer_get_expire_time,uint32_t,FuriTimer*
|
Function,+,furi_timer_get_expire_time,uint32_t,FuriTimer*
|
||||||
Function,+,furi_timer_is_running,uint32_t,FuriTimer*
|
Function,+,furi_timer_is_running,uint32_t,FuriTimer*
|
||||||
|
|||||||
|
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,76.0,,
|
Version,+,77.0,,
|
||||||
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
|
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.h,,
|
||||||
Header,+,applications/services/bt/bt_service/bt_keys_storage.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,-,ftrylockfile,int,FILE*
|
||||||
Function,-,funlockfile,void,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,-,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_ms,void,uint32_t
|
||||||
Function,+,furi_delay_tick,void,uint32_t
|
Function,+,furi_delay_tick,void,uint32_t
|
||||||
Function,+,furi_delay_until_tick,FuriStatus,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_suspend,void,FuriThreadId
|
||||||
Function,+,furi_thread_yield,void,
|
Function,+,furi_thread_yield,void,
|
||||||
Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*"
|
Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*"
|
||||||
|
Function,+,furi_timer_flush,void,
|
||||||
Function,+,furi_timer_free,void,FuriTimer*
|
Function,+,furi_timer_free,void,FuriTimer*
|
||||||
Function,+,furi_timer_get_expire_time,uint32_t,FuriTimer*
|
Function,+,furi_timer_get_expire_time,uint32_t,FuriTimer*
|
||||||
Function,+,furi_timer_is_running,uint32_t,FuriTimer*
|
Function,+,furi_timer_is_running,uint32_t,FuriTimer*
|
||||||
|
|||||||
|
@@ -87,6 +87,8 @@ void ble_glue_init(void) {
|
|||||||
TL_Init();
|
TL_Init();
|
||||||
|
|
||||||
ble_glue->shci_mtx = furi_mutex_alloc(FuriMutexTypeNormal);
|
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
|
// FreeRTOS system task creation
|
||||||
ble_event_thread_start();
|
ble_event_thread_start();
|
||||||
@@ -248,7 +250,9 @@ void ble_glue_stop(void) {
|
|||||||
ble_event_thread_stop();
|
ble_event_thread_stop();
|
||||||
// Free resources
|
// Free resources
|
||||||
furi_mutex_free(ble_glue->shci_mtx);
|
furi_mutex_free(ble_glue->shci_mtx);
|
||||||
|
ble_glue->shci_mtx = NULL;
|
||||||
furi_timer_free(ble_glue->hardfault_check_timer);
|
furi_timer_free(ble_glue->hardfault_check_timer);
|
||||||
|
ble_glue->hardfault_check_timer = NULL;
|
||||||
|
|
||||||
ble_glue_clear_shared_memory();
|
ble_glue_clear_shared_memory();
|
||||||
free(ble_glue);
|
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) {
|
static void ble_sys_status_not_callback(SHCI_TL_CmdStatus_t status) {
|
||||||
switch(status) {
|
switch(status) {
|
||||||
case SHCI_TL_CmdBusy:
|
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;
|
break;
|
||||||
case SHCI_TL_CmdAvailable:
|
case SHCI_TL_CmdAvailable:
|
||||||
furi_mutex_release(ble_glue->shci_mtx);
|
furi_check(furi_mutex_release(ble_glue->shci_mtx) == FuriStatusOk);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ BleEventFlowStatus ble_event_app_notification(void* pckt) {
|
|||||||
event_pckt = (hci_event_pckt*)((hci_uart_pckt*)pckt)->data;
|
event_pckt = (hci_event_pckt*)((hci_uart_pckt*)pckt)->data;
|
||||||
|
|
||||||
furi_check(gap);
|
furi_check(gap);
|
||||||
furi_mutex_acquire(gap->state_mutex, FuriWaitForever);
|
furi_check(furi_mutex_acquire(gap->state_mutex, FuriWaitForever) == FuriStatusOk);
|
||||||
|
|
||||||
switch(event_pckt->evt) {
|
switch(event_pckt->evt) {
|
||||||
case HCI_DISCONNECTION_COMPLETE_EVT_CODE: {
|
case HCI_DISCONNECTION_COMPLETE_EVT_CODE: {
|
||||||
@@ -304,7 +304,7 @@ BleEventFlowStatus ble_event_app_notification(void* pckt) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
furi_mutex_release(gap->state_mutex);
|
furi_check(furi_mutex_release(gap->state_mutex) == FuriStatusOk);
|
||||||
|
|
||||||
return BleEventFlowEnable;
|
return BleEventFlowEnable;
|
||||||
}
|
}
|
||||||
@@ -490,7 +490,7 @@ static void gap_advertise_stop(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void gap_start_advertising(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) {
|
if(gap->state == GapStateIdle) {
|
||||||
gap->state = GapStateStartingAdv;
|
gap->state = GapStateStartingAdv;
|
||||||
FURI_LOG_I(TAG, "Start advertising");
|
FURI_LOG_I(TAG, "Start advertising");
|
||||||
@@ -498,18 +498,18 @@ void gap_start_advertising(void) {
|
|||||||
GapCommand command = GapCommandAdvFast;
|
GapCommand command = GapCommandAdvFast;
|
||||||
furi_check(furi_message_queue_put(gap->command_queue, &command, 0) == FuriStatusOk);
|
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) {
|
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) {
|
if(gap->state > GapStateIdle) {
|
||||||
FURI_LOG_I(TAG, "Stop advertising");
|
FURI_LOG_I(TAG, "Stop advertising");
|
||||||
gap->enable_adv = false;
|
gap->enable_adv = false;
|
||||||
GapCommand command = GapCommandAdvStop;
|
GapCommand command = GapCommandAdvStop;
|
||||||
furi_check(furi_message_queue_put(gap->command_queue, &command, 0) == FuriStatusOk);
|
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) {
|
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 gap_get_state(void) {
|
||||||
GapState state;
|
GapState state;
|
||||||
if(gap) {
|
if(gap) {
|
||||||
furi_mutex_acquire(gap->state_mutex, FuriWaitForever);
|
furi_check(furi_mutex_acquire(gap->state_mutex, FuriWaitForever) == FuriStatusOk);
|
||||||
state = gap->state;
|
state = gap->state;
|
||||||
furi_mutex_release(gap->state_mutex);
|
furi_check(furi_mutex_release(gap->state_mutex) == FuriStatusOk);
|
||||||
} else {
|
} else {
|
||||||
state = GapStateUninitialized;
|
state = GapStateUninitialized;
|
||||||
}
|
}
|
||||||
@@ -577,17 +577,21 @@ GapState gap_get_state(void) {
|
|||||||
|
|
||||||
void gap_thread_stop(void) {
|
void gap_thread_stop(void) {
|
||||||
if(gap) {
|
if(gap) {
|
||||||
furi_mutex_acquire(gap->state_mutex, FuriWaitForever);
|
furi_check(furi_mutex_acquire(gap->state_mutex, FuriWaitForever) == FuriStatusOk);
|
||||||
gap->enable_adv = false;
|
gap->enable_adv = false;
|
||||||
GapCommand command = GapCommandKillThread;
|
GapCommand command = GapCommandKillThread;
|
||||||
furi_message_queue_put(gap->command_queue, &command, FuriWaitForever);
|
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_join(gap->thread);
|
||||||
furi_thread_free(gap->thread);
|
furi_thread_free(gap->thread);
|
||||||
|
gap->thread = NULL;
|
||||||
// Free resources
|
// Free resources
|
||||||
furi_mutex_free(gap->state_mutex);
|
furi_mutex_free(gap->state_mutex);
|
||||||
|
gap->state_mutex = NULL;
|
||||||
furi_message_queue_free(gap->command_queue);
|
furi_message_queue_free(gap->command_queue);
|
||||||
|
gap->command_queue = NULL;
|
||||||
furi_timer_free(gap->advertise_timer);
|
furi_timer_free(gap->advertise_timer);
|
||||||
|
gap->advertise_timer = NULL;
|
||||||
|
|
||||||
ble_event_dispatcher_reset();
|
ble_event_dispatcher_reset();
|
||||||
free(gap);
|
free(gap);
|
||||||
@@ -604,7 +608,7 @@ static int32_t gap_app(void* context) {
|
|||||||
FURI_LOG_E(TAG, "Message queue get error: %d", status);
|
FURI_LOG_E(TAG, "Message queue get error: %d", status);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
furi_mutex_acquire(gap->state_mutex, FuriWaitForever);
|
furi_check(furi_mutex_acquire(gap->state_mutex, FuriWaitForever) == FuriStatusOk);
|
||||||
if(command == GapCommandKillThread) {
|
if(command == GapCommandKillThread) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -615,7 +619,7 @@ static int32_t gap_app(void* context) {
|
|||||||
} else if(command == GapCommandAdvStop) {
|
} else if(command == GapCommandAdvStop) {
|
||||||
gap_advertise_stop();
|
gap_advertise_stop();
|
||||||
}
|
}
|
||||||
furi_mutex_release(gap->state_mutex);
|
furi_check(furi_mutex_release(gap->state_mutex) == FuriStatusOk);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ bool furi_hal_spi_bus_trx_dma(
|
|||||||
furi_check(size > 0);
|
furi_check(size > 0);
|
||||||
|
|
||||||
// If scheduler is not running, use blocking mode
|
// 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);
|
return furi_hal_spi_bus_trx(handle, tx_buffer, rx_buffer, size, timeout_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ to exclude the API function. */
|
|||||||
#define INCLUDE_xTaskGetCurrentTaskHandle 1
|
#define INCLUDE_xTaskGetCurrentTaskHandle 1
|
||||||
#define INCLUDE_xTaskGetSchedulerState 1
|
#define INCLUDE_xTaskGetSchedulerState 1
|
||||||
#define INCLUDE_xTimerPendFunctionCall 1
|
#define INCLUDE_xTimerPendFunctionCall 1
|
||||||
|
#define INCLUDE_xTaskGetIdleTaskHandle 1
|
||||||
|
|
||||||
/* Workaround for various notification issues:
|
/* Workaround for various notification issues:
|
||||||
* - First one used by system primitives
|
* - 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 \
|
#define configMAX_SYSCALL_INTERRUPT_PRIORITY \
|
||||||
(configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
|
(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 <core/check.h>
|
|
||||||
#define configASSERT(x) \
|
|
||||||
if((x) == 0) { \
|
|
||||||
furi_crash("FreeRTOS Assert"); \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
|
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
|
||||||
standard names. */
|
standard names. */
|
||||||
#define vPortSVCHandler SVC_Handler
|
#define vPortSVCHandler SVC_Handler
|
||||||
#define xPortPendSVHandler PendSV_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() \
|
#define traceTASK_SWITCHED_IN() \
|
||||||
extern void furi_hal_mpu_set_stack_protection(uint32_t* stack); \
|
extern void furi_hal_mpu_set_stack_protection(uint32_t* stack); \
|
||||||
furi_hal_mpu_set_stack_protection((uint32_t*)pxCurrentTCB->pxStack); \
|
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
|
// 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 traceTASK_SWITCHED_OUT() FreeRTOS_errno = errno
|
||||||
|
|
||||||
#define portCLEAN_UP_TCB(pxTCB) \
|
/* Normal assert() semantics without relying on the provision of an assert.h
|
||||||
extern void furi_thread_cleanup_tcb_event(TaskHandle_t task); \
|
header file. */
|
||||||
furi_thread_cleanup_tcb_event(pxTCB)
|
#ifdef DEBUG
|
||||||
|
#define configASSERT(x) \
|
||||||
|
if((x) == 0) { \
|
||||||
|
furi_crash("FreeRTOS Assert"); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Must be last line of config because of recursion
|
||||||
|
#include <core/check.h>
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ int32_t init_task(void* context) {
|
|||||||
// Init flipper
|
// Init flipper
|
||||||
flipper_init();
|
flipper_init();
|
||||||
|
|
||||||
|
furi_background();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,7 +27,8 @@ int main(void) {
|
|||||||
// Flipper critical FURI HAL
|
// Flipper critical FURI HAL
|
||||||
furi_hal_init_early();
|
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
|
#ifdef FURI_RAM_EXEC
|
||||||
// Prevent entering sleep mode when executed from RAM
|
// Prevent entering sleep mode when executed from RAM
|
||||||
|
|||||||
Reference in New Issue
Block a user