From 5190aace88bba125383281f7f51816d911ad4ccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Mon, 14 Oct 2024 14:39:09 +0100 Subject: [PATCH 1/3] 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 --- applications/services/bt/bt_service/bt.c | 20 +++--- .../dialogs/dialogs_module_file_browser.c | 5 +- applications/services/rpc/rpc.c | 67 ++++++++++--------- furi/core/kernel.c | 5 +- furi/core/log.c | 17 +++-- furi/core/thread.c | 44 ++++++++---- furi/core/thread.h | 21 +++--- furi/core/thread_i.h | 7 ++ furi/core/timer.c | 39 ++++++----- furi/core/timer.h | 9 ++- furi/furi.c | 7 ++ furi/furi.h | 2 + targets/f18/api_symbols.csv | 4 +- targets/f7/api_symbols.csv | 4 +- targets/f7/ble_glue/ble_glue.c | 11 ++- targets/f7/ble_glue/gap.c | 28 ++++---- targets/f7/furi_hal/furi_hal_spi.c | 2 +- targets/f7/inc/FreeRTOSConfig.h | 29 ++++---- targets/f7/src/main.c | 5 +- 19 files changed, 204 insertions(+), 122 deletions(-) create mode 100644 furi/core/thread_i.h diff --git a/applications/services/bt/bt_service/bt.c b/applications/services/bt/bt_service/bt.c index d72e745ee..2eeeab286 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 12a7439e6..603c27cff 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 08a2c3f6d..41d55841e 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]); - } + 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); + } + 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_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_free(thread); - free(session); + furi_mutex_free(session->callbacks_mutex); + furi_thread_join(session->thread); + 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); - 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 f3f84e692..34c562bb3 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 f8110b46a..fb0c96711 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 3990dd63d..fd576ea72 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 c320fdbc1..ed7aa4553 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 000000000..c6b12a780 --- /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 01adbeb89..ddd82e331 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 00056db18..9d8df3dc6 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 f4e64ee09..bc7452f13 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 d75debe98..6ddf28577 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 7e612de86..2b04e3e40 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 02e184a8a..71d9213d8 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 73bb41bad..fe101b2c9 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 9cd33456b..732440ccf 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 49bcd48a1..2a7cb7c25 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 82cda2c6d..357019ea2 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 77961f0ef..21775f19a 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 From 421bd3e1f9484ce1100fcba6a50f12cc8fbe74fc Mon Sep 17 00:00:00 2001 From: Ruslan Nadyrshin <110516632+rnadyrshin@users.noreply.github.com> Date: Mon, 14 Oct 2024 17:47:12 +0400 Subject: [PATCH 2/3] Wi-Fi Devboard documentation rework (#3944) * New step-by-step documentation structure for Wi-Fi Devboard * Added a description of working under Windows * Added a description of switching Devboard operation mode (Black Magic, DAPLink) * The images for the documentation are uploaded to the CDN * The text in the sidebar, near the dolphin logo, changed from blue to black/white Co-authored-by: knrn64 <25254561+knrn64@users.noreply.github.com> Co-authored-by: Aleksandr Kutuzov --- .../devboard/Debugging via the Devboard.md | 88 +++++++++ .../devboard/Devboard debug modes.md | 33 ++++ .../Firmware update on Developer Board.md | 114 ++++++------ .../Get started with the Dev Board.md | 176 ++++-------------- .../Reading logs via the Dev Board.md | 18 +- .../USB connection to the Devboard.md | 22 +++ .../Wi-Fi connection to the Devboard.md | 60 ++++++ documentation/doxygen/dev_board.dox | 33 +++- documentation/doxygen/header.html | 2 +- documentation/fbt.md | 2 +- 10 files changed, 335 insertions(+), 213 deletions(-) create mode 100644 documentation/devboard/Debugging via the Devboard.md create mode 100644 documentation/devboard/Devboard debug modes.md create mode 100644 documentation/devboard/USB connection to the Devboard.md create mode 100644 documentation/devboard/Wi-Fi connection to the Devboard.md diff --git a/documentation/devboard/Debugging via the Devboard.md b/documentation/devboard/Debugging via the Devboard.md new file mode 100644 index 000000000..49888cdbc --- /dev/null +++ b/documentation/devboard/Debugging via the Devboard.md @@ -0,0 +1,88 @@ +# Debugging via the Devboard {#dev_board_debugging_guide} + +On this page, you'll learn about how debugging via the Wi-Fi Developer Board works. To illustrate this process, we'll start a debug session for Flipper Zero's firmware in VS Code using the native Flipper Build Tool. + +*** + +## Overview + +The Developer Board acts as the debug probe, which provides a bridge between the IDE (integrated development environment) with a debugger running on a host computer and the target microcontroller (in your Flipper Zero). The user controls the debugging process on the computer connected to the Developer Board via [Wi-Fi](#dev_board_wifi_connection) or [USB cable](#dev_board_usb_connection). + +\image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_hardware_CDN.jpg width=700 + +Data exchange between the Wi-Fi Developer Board and your Flipper Zero is conducted via the Serial Wire Debug interface. The following GPIO pins serve this purpose: + +- **Pin 10:** Serial Wire Clock (SWCLK) + +- **Pin 12:** Serial Wire Debug Data I/O (SWDIO) + +To learn more about Flipper Zero pinout, visit [GPIO & modules in Flipper Docs](https://docs.flipper.net/gpio-and-modules). + +*** + +## Prerequisites + +### Step 1. Installing Git + +You'll need Git installed on your computer to clone the firmware repository. If you don't have Git, install it following the [official installation guide](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git). + +### Step 2. Building the firmware + +Before starting debugging, you need to clone and build Flipper Zero firmware: + +1. Open the **Terminal** (on Linux & macOS) or **PowerShell** (on Windows) in the directory where you want to store the firmware source code. + +2. Clone the firmware repository: + + ``` + git clone --recursive https://github.com/flipperdevices/flipperzero-firmware.git + cd flipperzero-firmware + ``` + +3. Run the **Flipper Build Tool (FBT)** to build the firmware: + + ``` + ./fbt + ``` + +*** + +## Debugging the firmware + +From the **flipperzero-firmware** directory that you cloned earlier, run the following command: + +``` +./fbt flash +``` + +This will upload the firmware you've just built to your Flipper Zero via the Developer Board. After that, you can start debugging the firmware. We recommend using **VS Code** with the recommended extensions (as described below), and we have pre-made configurations for it. + +To debug in **VS Code**, do the following: + +1. In VS Code, open the **flipperzero-firmware** directory. + +2. You should see a notification about recommended extensions. Install them. + + If there were no notifications, open the **Extensions** tab, enter `@recommended` in the search bar, and install the workspace recommendations. + +3. Run the `./fbt vscode_dist` command. This will generate the VS Code configuration files needed for debugging. + +4. In VS Code, open the **Run and Debug** tab and select a debugger from the dropdown menu: + + - **Attach FW (blackmagic):** Can be used via **Wi-Fi** or **USB** + - **Attach FW (DAP):** Can be used via **USB** only + + Note that when debugging via USB, you need to make sure the selected debugger matches the debug mode on your Devboard. To check the debug mode on your Devboard, access the Devboard's web interface as described [here](#dev_board_wifi_connection) and check the **USB mode** field. If you want to use a different debug mode, enable this mode by following the steps in [Devboard debug modes](#dev_board_debug_modes). + +5. If needed, flash your Flipper Zero with the `./fbt flash` command, then click the ▷ **Start Debugging** button in the debug sidebar to start the debugging session. + +6. Note that starting a debug session halts the execution of the firmware, so you'll need to click the I▷ **Continue** button on the toolbar at the top of your VS Code window to continue execution. + +\image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_VS_Code.jpg width=900 + +> [!note] +> If you want to use a different debug mode on your Developer Board, visit [Devboard debug modes](#dev_board_debug_modes). +> +> If you want to read logs via the Developer Board, see [Reading logs via the Devboard](#dev_board_reading_logs). +> +> To learn about debugging in VS Code, see [VS Code official guide](https://code.visualstudio.com/docs/editor/debugging). diff --git a/documentation/devboard/Devboard debug modes.md b/documentation/devboard/Devboard debug modes.md new file mode 100644 index 000000000..a6550cbbb --- /dev/null +++ b/documentation/devboard/Devboard debug modes.md @@ -0,0 +1,33 @@ +# Devboard debug modes {#dev_board_debug_modes} + +The Wi-Fi Devboard for Flipper Zero supports **Black Magic** and **DAPLink** debug modes, and you can switch between them depending on your needs. Note that available modes depend on connection: + +- **Wi-Fi:** Only **Black Magic** mode is available. +- **USB:** Switch between **Black Magic** (default) and **DAPLink**. Learn more about switching debug modes for USB connection below. + +> [!note] +> Black Magic mode doesn't support RTOS threads, but you can still perform other debugging operations. + +*** + +## Switching debug modes for USB connection + +Switching debug modes for working via USB has to be done wirelessly (yes, you read that correctly). Additionally, depending on how the Devboard wireless connection is configured, you may need to follow different steps for **Wi-Fi access point mode** or **Wi-Fi client mode**: + +1. If the Devboard isn't connected to your Flipper Zero, turn off your Flipper Zero and connect the Developer Board, then turn the device back on. + +2. Access the Devboard's web interface: + + - [Wi-Fi access point mode](#wifi-access-point) + + - [Wi-Fi client mode](#wifi-client-mode) + +3. In the **WiFi** tab, click the **USB mode** option and select **BlackMagicProbe** or **DapLink**. + +4. Click **SAVE**, then click **REBOOT** to apply the changes. + +\image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_devboard_switching_modes_CDN.jpg width=700 + +> [!note] +> After switching debug modes on your Devboard, remember to select the same debugger in **VS Code** in the **Run and Debug** tab, and click the ▷ **Start Debugging** button. + diff --git a/documentation/devboard/Firmware update on Developer Board.md b/documentation/devboard/Firmware update on Developer Board.md index f6a81d97b..0b88e52be 100644 --- a/documentation/devboard/Firmware update on Developer Board.md +++ b/documentation/devboard/Firmware update on Developer Board.md @@ -1,122 +1,112 @@ # Firmware update on Developer Board {#dev_board_fw_update} -It's important to regularly update your Developer Board to ensure that you have access to the latest features and bug fixes. This tutorial will guide you through the necessary steps to update the firmware of your Developer Board. +It's important to regularly update your Developer Board to ensure that you have access to the latest features and bug fixes. This page will guide you through the necessary steps to update the firmware of your Developer Board. -This tutorial assumes that you're familiar with the basics of the command line. If you’re not, please refer to the [Windows](https://www.digitalcitizen.life/command-prompt-how-use-basic-commands/) or [MacOS/Linux](https://ubuntu.com/tutorials/command-line-for-beginners#1-overview) command line tutorials. +> [!note] +> This guide assumes that you're familiar with the basics of the command line. If you're new to it, we recommend checking out these [Windows](https://learn.microsoft.com/en-us/powershell/scripting/learn/ps101/01-getting-started?view=powershell-7.4) or [macOS/Linux](https://ubuntu.com/tutorials/command-line-for-beginners#1-overview) command line tutorials. *** -## Installing the micro Flipper Build Tool +## Step 1. Install the micro Flipper Build Tool -Micro Flipper Build Tool (uFBT) is a cross-platform tool that enables basic development tasks for Flipper Zero, such as building and debugging applications, flashing firmware, and creating VS Code development configurations. + is a cross-platform tool developed and supported by our team that enables basic development tasks for Flipper Zero, such as building and debugging applications, flashing firmware, creating VS Code development configurations, and flashing firmware to the Wi-Fi Developer Board. -Install uFBT on your computer by running the following command in the Terminal: +**On Linux & macOS:** -**For Linux & macOS:** +Run the following command in the Terminal: -```text +``` python3 -m pip install --upgrade ufbt ``` -**For Windows:** +**On Windows:** -```text -py -m pip install --upgrade ufbt -``` +1. Download the latest version of Python on +2. Run the following command in the PowerShell -If you want to learn more about uFBT, visit [the project's page](https://pypi.org/project/ufbt/). + ``` + py -m pip install --upgrade ufbt + ``` *** -## Connecting the Developer Board to your computer +## Step 2. Connect the Devboard to PC + +To update the firmware, you need to switch your Developer Board to Bootloader mode, connect to a PC via a USB cable, and make sure that the PC detects the Developer Board: 1. List all of the serial devices on your computer. - **Windows** + - **macOS:** Run the `ls /dev/cu.*` command in the Terminal. - On Windows, go to Device Manager and expand the Ports (COM & LPT) section. + - **Linux:** Run the `ls /dev/tty*` command in the Terminal. - **macOS** - - On macOS, you can run the following command in the Terminal: - - ```text - ls /dev/cu.* - ``` - - **Linux** - - On Linux, you can run the following command in the Terminal: - - ```text - ls /dev/tty* - ``` - - View the devices in the list. + - **Windows:** Go to **Device Manager** and expand the **Ports (COM & LPT)** section. 2. Connect the Developer Board to your computer using a USB-C cable. -![The Developer Board in Wired mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/Aq7gfMI-m_5H6sGGjwb4I_monosnap-miro-2023-07-19-19-47-39.jpg) + + \image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_update_wired_connection.jpg width=700 3. Switch your Developer Board to Bootloader mode: - 3.1. Press and hold the **BOOT** button. + 1. Press and hold the **BOOT** button. + 2. Press the **RESET** button while holding the **BOOT** button. + 3. Release the **BOOT** button. - 3.2. Press the **RESET** button while holding the **BOOT** button. + \image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_reboot_to_bootloader.png width=700 - 3.3. Release the **BOOT** button.\ -![You can easily switch the Dev Board to Bootloader mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/KynP9iT6sJ3mXLaLyI82__image.png) - -4. Repeat Step 1 and view the name of your Developer Board that appeared in the list. - - For example, on macOS: - - ```text - /dev/cu.usbmodem01 - ``` +4. Repeat **Step 1** and view the name of your Developer Board that appeared in the list. *** -## Flashing the firmware +## Step 3. Flash the firmware -To flash the firmware onto your Developer Board, run the following command in the terminal: +**On Linux & macOS:** -```text +``` python3 -m ufbt devboard_flash ``` +**On Windows:** Run the following command in the PowerShell: + +``` +py -m ufbt devboard_flash +``` + You should see the following message: `WiFi board flashed successfully`. -## If flashing failed +### If flashing failed -If you get an error message during the flashing process, such as this: +Occasionally, you might get an error message during the flashing process, such as: -```text +``` A fatal error occurred: Serial data stream stopped: Possible serial noise or corruption. ``` -Or this: +*or* -```text +``` FileNotFoundError: [Errno 2] No such file or directory: '/dev/cu.usbmodem01' ``` -Try doing the following: +To fix it, try doing the following: -* Disconnect the Developer Board from your computer, then reconnect it. +- Disconnect the Developer Board from your computer, then reconnect it. After that, switch your Developer Board to Bootloader mode once again, as described in -* Use a different USB port on your computer. +- Use a different USB port on your computer. -* Use a different USB-C cable. +- Use a different USB-C cable. *** -## Finishing the installation - -After flashing the firmware: +## Step 4. Finish the installation 1. Reboot the Developer Board by pressing the **RESET** button. -![Reset the Developer Board](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/rcQeKARgrVwa51tLoo-qY_monosnap-miro-2023-07-20-18-29-33.jpg) + + \image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_reboot_after_flashing.jpg width=700 2. Disconnect and reconnect the USB-C cable. -The Developer Board should appear as a serial device on your computer. Now, you can use it with the Black Magic Debug client of your choice. + You've successfully updated the firmware of your Developer Board! + +If you followed the **Get started with the Devboard** guide, you're ready for the next step: [Step 3. Plug the Devboard into Flipper Zero](#dev_board_get_started_step-3). + diff --git a/documentation/devboard/Get started with the Dev Board.md b/documentation/devboard/Get started with the Dev Board.md index 04fa9d358..141bf6411 100644 --- a/documentation/devboard/Get started with the Dev Board.md +++ b/documentation/devboard/Get started with the Dev Board.md @@ -1,178 +1,80 @@ # Get started with the Dev Board {#dev_board_get_started} -The Wi-Fi Developer Board serves as a tool to debug the Flipper Zero firmware. To debug the firmware, the initial step involves compiling the firmware from its source code. This process enables the debugging functionality within the firmware and generates all the necessary files required for debugging purposes. +\image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_developer_board_box_CDN.jpg width=700 -> **NOTE:** Building and debugging the Flipper Zero firmware is fully supported on MacOS and Linux. Support for Windows is in beta test. +Before you start using your Devboard, you need to prepare your Flipper Zero and Devboard for debugging. In this guide, we'll walk you through all the necessary steps and provide links to explore the Devboard's capabilities further. *** -## Updating the firmware of your Developer Board +## Step 1. Enable Debug Mode on your Flipper Zero -Update the firmware of your Developer Board before using it. For more information, visit [Firmware update on Developer Board](https://docs.flipperzero.one/development/hardware/wifi-debugger-module/update). +Since the main purpose of the Developer board is to debug applications on Flipper Zero, you first need to enable Debug Mode. To do so, go to **Settings → System** and set **Debug** to **ON**. + +\image html https://cdn.flipperzero.one/Flipper_Zero_enamble_debug_CDN.jpg width=700 + +> [!note] +> Debug Mode needs to be re-enabled after each update of Flipper Zero's firmware. + +Debug Mode allows you to debug your apps for Flipper Zero, as well as access debugging options in apps via the user interface and CLI. To learn more about Flipper Zero CLI, visit [Command-line interface in Flipper Docs](https://docs.flipper.net/development/cli). + +\image html https://cdn.flipperzero.one/Flipper_Zero_Command_Line_Interface_CDN.jpg width=700 *** -## Installing Git +## Step 2. Update firmware on the Developer Board -You'll need Git installed on your computer to clone the firmware repository. If you don't have Git, install it by doing the following: - -* **MacOS** - - On MacOS, install the **Xcode Command Line Tools** package, which includes Git as one of the pre-installed command-line utilities, by running in the Terminal the following command: - - ```text - xcode-select --install - ``` - -* **Linux** - - On Linux, you can install Git using your package manager. For example, on Ubuntu, run in the Terminal the following command: - - ```text - sudo apt install git - ``` - -For other distributions, refer to your package manager documentation. +The Developer Board comes with stock firmware that may not include all the latest features and bug fixes. To ensure optimal performance, please update your board's firmware using the instructions in [Firmware update on Devboard](#dev_board_fw_update). *** -## Building the firmware +## Step 3. Plug the Devboard into Flipper Zero {#dev_board_get_started_step-3} -First, clone the firmware repository: +Once your Developer Board firmware is up to date, you can proceed to plug it into your Flipper Zero. Two important things to keep in mind: -```text -git clone --recursive https://github.com/flipperdevices/flipperzero-firmware.git -cd flipperzero-firmware -``` +1. **Power off your Flipper Zero before plugging in the Developer Board.** -Then, run the **Flipper Build Tool** (FBT) to build the firmware: + If you skip this step, you may corrupt the data stored on the microSD card. Connecting external modules with a large capacitive load may affect the microSD card's power supply since both the microSD card and external module are powered from the same 3.3 V power source inside Flipper Zero. -```text -./fbt -``` +2. **Make sure the Developer Board is inserted all the way in.** + + If your Flipper Zero isn't in a silicone case, insert the module all the way in so there is no gap between your Flipper Zero and the Devboard. You may need to apply more force to insert it completely. After that, press and hold the **BACK** button to power on your Flipper Zero. + + \image html https://cdn.flipperzero.one/Flipper_Zero_external_module_without_case_CDN.jpg width=700 + + If your Flipper Zero is in a silicone case, insert the module all the way in so there is no gap in the middle between the silicone case and the module. After that, press and hold the **BACK** button to power on your Flipper Zero. + + \image html https://cdn.flipperzero.one/Flipper_Zero_external_module_with_case_CDN.jpg width=700 *** -## Connecting the Developer Board +## Step 4. Connect to a computer -The Developer Board can work in the **Wired** mode and two **Wireless** modes: **Wi-Fi access point (AP)** mode and **Wi-Fi client (STA)** mode. The Wired mode is the simplest to set up, but requires a USB Type-C cable. The Wireless modes are more complex to set up, but they allow you to debug your Flipper Zero wirelessly. +Now, you can connect the Developer Board to your computer via USB or Wi-Fi, depending on your needs. We described both methods in separate documents: - > **NOTE:** Use the following credentials when connecting to the Developer Board in **Wi-Fi access point** mode:\n - Name: **blackmagic**\n - Password: **iamwitcher** - -## Wired - -![The Developer Board in Wired mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/jZdVlRTPVdSQVegzCyXp7_monosnap-miro-2023-06-22-16-28-06.jpg) - -To connect the Developer Board in **Wired** mode, do the following: - -1. Cold-plug the Developer Board by turning off your Flipper Zero and connecting the Developer Board, and then turning it back on. - -2. On your computer, open the **Terminal** and run the following: - - * **MacOS** - - ```text - ls /dev/cu.* - ``` - - * **Linux** - - ```text - ls /dev/tty* - ``` - - Note the list of devices. - -3. Connect the Developer Board to your computer via a USB-C cable. - -4. Rerun the command. Two new devices have to appear: this is the Developer Board. - - > **NOTE:** If the Developer Board doesn't appear in the list of devices, try using a different cable, USB port, or computer. - > - > **NOTE:** Flipper Zero logs can only be viewed when the Developer Board is connected via USB. The option to view logs over Wi-Fi will be added in future updates. For more information, visit [Reading logs via the Dev Board](https://docs.flipperzero.one/development/hardware/wifi-debugger-module/reading-logs). - -## Wireless - -### Wi-Fi access point (AP) mode - -![The Developer Board in Wi-Fi access point mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/tKRTMHAuruiLSEce2a8Ve_monosnap-miro-2023-06-22-16-39-17.jpg) - -Out of the box, the Developer Board is configured to work as a **Wi-Fi access point**. This means it'll create its own Wi-Fi network to which you can connect. If your Developer Board doesn't create a Wi-Fi network, it is probably configured to work in **Wi-Fi client** mode. To reset your Developer Board back to **Wi-Fi access point** mode, press and hold the **BOOT** button for 10 seconds, then wait for the module to reboot. - -![You can reconfigure the Developer Board mode by pressing and holding the BOOT button](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/57eELJsAwMxeZCEA1NMJw_monosnap-miro-2023-06-22-20-33-27.jpg) - -To connect the Developer Board in **Wi-Fi access point** mode, do the following: - -1. Cold-plug the Developer Board by turning off your Flipper Zero and connecting the Developer Board, and then turning it back on. - -2. Open Wi-Fi settings on your client device (phone, laptop, or other). - -3. Connect to the network: - - * Name: **blackmagic** - - * Password: **iamwitcher** - -4. To configure the Developer Board, open a browser and go to `http://192.168.4.1`. - -### Wi-Fi client (STA) mode - -![The Developer Board in Wi-Fi client mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/xLQpFyYPfUS5Cx0uQhrNd_monosnap-miro-2023-06-23-12-34-36.jpg) - -To connect the Developer Board in **Wi-Fi client** mode, you need to configure it to connect to your Wi-Fi network by doing the following: - -1. Cold-plug the Developer Board by turning off your Flipper Zero and connecting the Developer Board, and then turning it back on. - -2. Connect to the Developer Board in **Wi-Fi access point** mode. - -3. In a browser, go to the configuration page on `http://192.168.4.1`. - -4. Select the **STA** mode and enter your network's **SSID** (name) and **password**. For convenience, you can click the **+** button to see the list of nearby networks. - -5. Save the configuration and reboot the Developer Board. - -![In the Wi-Fi tab, you can set the Developer Board mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/klbLVj8lz2bEvm7j4wRaj_monosnap-miro-2023-06-23-13-06-32.jpg) - -After rebooting, the Developer Board connects to your Wi-Fi network. You can connect to the device using the mDNS name **blackmagic.local** or the IP address it got from your router (you'll have to figure this out yourself, every router is different). - -After connecting to your debugger via , you can find its IP address in the **SYS** tab. You can also change the debugger's mode to **AP** or **STA** there. - -![In the SYS tab, you can view the IP address of your Developer Board](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/5XbUptlfqzlV0p6hRUqiG_monosnap-miro-2023-06-22-18-11-30.jpg) +- **[Via USB cable](#dev_board_usb_connection)** for debugging in DAP Link or Black Magic mode, and reading logs. +- [Via Wi-Fi](#dev_board_wifi_connection) for debugging in Black Magic mode. *** -## Debugging the firmware +## Next steps -Open the **Terminal** in the **flipperzero-firmware** directory that you cloned earlier and run the following command: +You are ready to debug now! To further explore what you can do with the Devboard, check out these pages: -```text -./fbt flash -``` +- [Debugging via the Devboard](#dev_board_debugging_guide) +- [Devboard debug modes](#dev_board_debug_modes) +- [Reading logs via the Devboard](#dev_board_reading_logs) + +These guides should help you get started with your Devboard. If you have any questions or you want to share your experience, don't hesitate to join our community on [Reddit](https://www.reddit.com/r/flipperzero/) and [Discord](https://discord.com/invite/flipper), where we have a dedicated #wifi-devboard channel. -This will upload the firmware you've just built to your Flipper Zero via the Developer Board. After that, you can start debugging the firmware using the [GDB](https://www.gnu.org/software/gdb/) debugger. We recommend using **VSCode** with the recommended extensions, and we have pre-made configurations for it. -To debug in **VSCode**, do the following: -1. In VSCode, open the **flipperzero-firmware** directory. -2. You should see a notification about recommended extensions. Install them. - If there were no notifications, open the **Extensions** tab, enter `@recommended` in the search bar, and install the workspace recommendations. -3. In the **Terminal**, run the `./fbt vscode_dist` command. This will generate the VSCode configuration files needed for debugging. -4. In VSCode, open the **Run and Debug** tab and select **Attach FW (blackmagic)** from the dropdown menu. -5. If needed, flash your Flipper Zero with the `./fbt flash` command, then click the **Play** button in the debug sidebar to start the debugging session. -6. Note that starting a debug session halts the execution of the firmware, so you'll need to click the **Continue** button on the toolbar at the top of your VSCode window to continue execution. -![Click Continue in the toolbar to continue execution of the firmware](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/lp8ygGaZ3DvWD3OSI9yGO_monosnap-miro-2023-06-23-17-58-09.jpg) -To learn about debugging, visit the following pages: -* [Debugging with GDB](https://sourceware.org/gdb/current/onlinedocs/gdb.pdf) -* [Debugging in VS Code](https://code.visualstudio.com/docs/editor/debugging) diff --git a/documentation/devboard/Reading logs via the Dev Board.md b/documentation/devboard/Reading logs via the Dev Board.md index c2daf83ac..56d0c87ef 100644 --- a/documentation/devboard/Reading logs via the Dev Board.md +++ b/documentation/devboard/Reading logs via the Dev Board.md @@ -8,9 +8,9 @@ The Developer Board allows you to read Flipper Zero logs via UART. Unlike readin ## Setting the log level -Depending on your needs, you can set the log level by going to **Main Menu → Settings → Log Level**. To learn more about logging levels, visit [Settings](https://docs.flipperzero.one/basics/settings#d5TAt). +Depending on your needs, you can set the log level by going to **Main Menu → Settings → Log Level**. To learn more about logging levels, visit [Settings](https://docs.flipper.net/basics/settings#d5TAt). -![You can manually set the preferred log level](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/INzQMw8QUsG9PXi30WFS0_monosnap-miro-2023-07-11-13-29-47.jpg) +\image html https://cdn.flipperzero.one/Flipper_Zero_log_level.jpg "You can manually set the preferred log level" width=700 *** @@ -18,9 +18,9 @@ Depending on your needs, you can set the log level by going to **Main Menu → S Depending on your operating system, you need to install an additional application on your computer to read logs via the Developer Board: -### MacOS +### macOS -On MacOS, you need to install the **minicom** communication program by doing the following: +On macOS, you need to install the **minicom** communication program by doing the following: 1. [Install Homebrew](https://brew.sh/) by running the following command in the Terminal: @@ -47,7 +47,7 @@ After installation of minicom on your macOS computer, you can connect to the Dev Note the list of devices. 3. Connect the developer board to your computer using a USB Type-C cable. -![Connect the developer board with a USB-C cable](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/iPpsMt2-is4aIjiVeFu5t_hjxs2i1oovrnps74v5jgsimage.png) +\image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_developer_board_wired.png width=700 4. Rerun the command. Two new devices have to appear: this is the Developer Board. @@ -100,7 +100,7 @@ After installation of minicom on your Linux computer, you can connect to the Dev Note the list of devices. 3. Connect the developer board to your computer using a USB Type-C cable. -![Connect the developer board with a USB-C cable](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/iPpsMt2-is4aIjiVeFu5t_hjxs2i1oovrnps74v5jgsimage.png) +\image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_developer_board_wired.png width=700 4. Rerun the command. Two new devices have to appear: this is the Developer Board. @@ -143,17 +143,17 @@ On Windows, do the following: 2. Cold-plug the Developer Board into your Flipper Zero by turning off the Flipper Zero, connecting the developer board, and then turning it back on. 3. Connect the developer board to your computer using a USB Type-C cable. -![Connect the developer board with a USB-C cable](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/iPpsMt2-is4aIjiVeFu5t_hjxs2i1oovrnps74v5jgsimage.png) +\image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_developer_board_wired.png width=700 4. Find the serial port that the developer board is connected to by going to **Device Manager → Ports (COM & LPT)** and looking for a new port that appears when you connect the Wi-Fi developer board. -![Find the serial port in your Device Manager](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/KKLQJK1lvqmI5iab3d__C_image.png) +\image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_Device_Manager.png width=700 5. Run the PuTTY application and select **Serial** as the connection type. 6. Enter the port number you found in the previous step into the **Serial line** field. 7. Set the **Speed** parameter to **230400** and click **Open**. -![Set speed to 230400](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/ROBSJyfQ_CXiy4GUZcPbs_monosnap-miro-2023-07-12-13-56-47.jpg) +\image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_PuTTy.jpg width=700 8. View logs of your Flipper Zero in the PuTTY terminal window. diff --git a/documentation/devboard/USB connection to the Devboard.md b/documentation/devboard/USB connection to the Devboard.md new file mode 100644 index 000000000..af0d9113d --- /dev/null +++ b/documentation/devboard/USB connection to the Devboard.md @@ -0,0 +1,22 @@ +# USB connection to the Devboard {#dev_board_usb_connection} + +\image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_devboard_USB_connection_CDN.jpg width=700 + +To connect to the Developer Board via USB, do the following: + +1. If the Devboard isn't connected to your Flipper Zero, turn off your Flipper Zero and connect the Developer Board to it. Then, turn your Flipper Zero back on. + +2. On your computer, check the list of serial devices. + + - **macOS:** On your computer, run `ls /dev/cu.*` in the Terminal. + + - **Linux:** On your computer, run `ls /dev/tty*` in the Terminal. + + - **Windows:** Go to **Device Manager** and expand the **Ports (COM & LPT)** section. + +3. Connect the Devboard to your computer via a USB-C cable. + +4. Repeat **Step 2**. Two new devices will appear — this is the Developer Board. + +> [!warning] +> If the Developer Board doesn't appear in the list of devices, try using a different cable, USB port, or computer. \ No newline at end of file diff --git a/documentation/devboard/Wi-Fi connection to the Devboard.md b/documentation/devboard/Wi-Fi connection to the Devboard.md new file mode 100644 index 000000000..fd3bc3249 --- /dev/null +++ b/documentation/devboard/Wi-Fi connection to the Devboard.md @@ -0,0 +1,60 @@ +# Wi-Fi connection to the Devboard {#dev_board_wifi_connection} + +You can connect to the Developer Board wirelessly in two ways: + +- **Wi-Fi access point mode (default):** The Devboard creates its own Wi-Fi network, which you can connect to in order to access its web interface and debug via Wi-Fi. The downside is that you will need to disconnect from your current Wi-Fi network, resulting in a loss of internet connection. + +- **Wi-Fi client mode:** You can connect to the Devboard through an existing Wi-Fi network, allowing you to access the Devboard web interface and debug via Wi-Fi without losing your internet connection. + +Let's go over both of these modes below. + +*** + +## Wi-Fi access point (AP) mode {#wifi-access-point} + +\image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_devboard_Access_Point_CDN.jpg width=700 + +Out of the box, the Developer Board is configured to work as a Wi-Fi access point. To connect the Developer Board in this mode, do the following: + +1. Plug the Wi-Fi Devboard into your Flipper Zero by turning off your Flipper Zero and connecting the Developer Board, and then turning it back on. + +2. Open Wi-Fi settings on your client device (phone, laptop, or other). + +3. Connect to the network: + + Name: `blackmagic` + Password: `iamwitcher` + + If your computer fails to find the **blackmagic** network, read the [troubleshooting section](#wifi-access-point_troubleshooting) below. + +4. To access the Devboard's web interface, open a browser and go to or . + +### If your computer fails to find the black magic network {#wifi-access-point_troubleshooting} + +- Reset Wi-Fi connection on your computer. + +- The Developer Board is probably configured to work in Wi-Fi client mode. → Reset your Developer Board settings to default by pressing and holding the **BOOT** button for **10 seconds**, then wait for the Devboard to reboot. After the reset, the Devboard will work in Wi-Fi access point mode. + +\image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_reboot.jpg width=700 + +*** + +## Wi-Fi client (STA) mode {#wifi-client-mode} + +\image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_devboard_STA_CDN.jpg width=700 + +To connect the Developer Board in **Wi-Fi client** mode, you need to configure it to connect to your Wi-Fi network by doing the following: + +1. Plug the Wi-Fi Devboard into your Flipper Zero by turning off your Flipper Zero and connecting the Developer Board, and then turning the device back on. + +2. Connect to the Developer Board in [Wi-Fi access point](#wifi-access-point) mode. + +3. In a browser, go to the Devboard's web interface at or . + +4. Select the **STA** mode and enter your network's **SSID** (name) and **password**. For convenience, you can click the **+** button to see the list of nearby 2.4 GHz networks (5 GHz networks aren't supported). + +5. Save the configuration and reboot the Developer Board. + + \image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_devboard_connect_to_WiFi_CDN.jpg width=700 + +6. Now, you can access the Devboard's web interface at [http://blackmagic.local](https://blackmagic.local) via the existing Wi-Fi network without losing connection to the internet. diff --git a/documentation/doxygen/dev_board.dox b/documentation/doxygen/dev_board.dox index 6caa44c70..8d5a2bf35 100644 --- a/documentation/doxygen/dev_board.dox +++ b/documentation/doxygen/dev_board.dox @@ -1,10 +1,37 @@ /** -@page dev_board Developer Board +@page dev_board Wi-Fi Developer Board -[ESP32-based development board](https://shop.flipperzero.one/collections/flipper-zero-accessories/products/wifi-devboard). +\image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_devboard_laptop_CDN.jpg width=700 + +Wi-Fi-enabled Developer Board brings debugging and firmware update capabilities to your Flipper Zero. The Developer Board is based on the ESP32-S2 MCU with custom firmware incorporating Black Magic Debug and CMSIS-DAP, and is built with ESP-IDF. It can flash and debug various microprocessors and microcontrollers (including the one used in your Flipper Zero) via Wi-Fi or USB cable. + +The Developer Board provides a debug interface, allowing developers to halt program execution, set breakpoints, inspect variables and memory, and step through code execution. + +
+Get your Wi-Fi Developer Board +
+
+ +Check out these guides to get started with the Devboard: - @subpage dev_board_get_started — Quick start for new users +- @subpage dev_board_fw_update — Keep the Developer Board up to date +- @subpage dev_board_usb_connection — Instructions for Windows, macOS and Linux +- @subpage dev_board_wifi_connection — Instructions for Windows, macOS and Linux +- @subpage dev_board_debugging_guide — Learn how it works +- @subpage dev_board_debug_modes — Available modes and how to switch between them - @subpage dev_board_reading_logs — Find out what is currently happening on the system -- @subpage dev_board_fw_update — Keep the developer board up to date + +## Hardware + +The Developer Board is equipped with an [ESP32-S2-WROVER](https://www.espressif.com/en/products/socs/esp32-s2) module, which includes built-in Wi-Fi capabilities. It also offers GPIO pins for easy connectivity to various targets. Additionally, the Developer Board features a USB Type-C connector for data transfer and power supply. For user interaction, the Developer Board has tactile switches. + +\image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_developer_board_hardware_CDN.jpg width=700 + +## Additional resources + +To learn more about the Wi-Fi Developer Board hardware, visit [Schematics in Flipper Docs](https://docs.flipperzero.one/development/hardware/wifi-debugger-module/schematics). + +For additional information about Flipper Zero GPIO pins, visit [GPIO & modules in Flipper Docs](https://docs.flipperzero.one/gpio-and-modules). */ diff --git a/documentation/doxygen/header.html b/documentation/doxygen/header.html index 5cc0aba38..e987e39aa 100644 --- a/documentation/doxygen/header.html +++ b/documentation/doxygen/header.html @@ -52,7 +52,7 @@ $extrastylesheet -
$projectname $projectnumber +
$projectname $projectnumber
$projectbrief
diff --git a/documentation/fbt.md b/documentation/fbt.md index 59f6aa154..2635a43fc 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -44,7 +44,7 @@ To run cleanup (think of `make clean`) for specified targets, add the `-c` optio ## VSCode integration -`fbt` includes basic development environment configuration for VS Code. Run `./fbt vscode_dist` to deploy it. That will copy the initial environment configuration to the `.vscode` folder. After that, you can use that configuration by starting VS Code and choosing the firmware root folder in the "File > Open Folder" menu. +`fbt` includes basic development environment configuration for VS Code. Run `./fbt vscode_dist` to deploy it. That will copy the initial environment configuration to the `.vscode` folder. After that, you can use that configuration by starting VS Code and choosing the firmware root folder in the "File > Open Folder" menu. To use language servers other than the default VS Code C/C++ language server, use `./fbt vscode_dist LANG_SERVER=` instead. Currently `fbt` supports the default language server (`cpptools`) and `clangd`. From d9d3867ce19fbfba92647187ef2820eb234020de Mon Sep 17 00:00:00 2001 From: SUMUKH <130692934+sumukhj1219@users.noreply.github.com> Date: Mon, 14 Oct 2024 20:03:51 +0530 Subject: [PATCH 3/3] Fixes Mouse Clicker Should have a "0" value setting for "as fast as possible" #3876 (#3894) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fixes mouse clicking rate * Hid: limit max clicks to 100/s, rewrite code to make it more robust Co-authored-by: あく --- .../system/hid_app/views/hid_mouse_clicker.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/applications/system/hid_app/views/hid_mouse_clicker.c b/applications/system/hid_app/views/hid_mouse_clicker.c index 0bb815249..e289b7179 100644 --- a/applications/system/hid_app/views/hid_mouse_clicker.c +++ b/applications/system/hid_app/views/hid_mouse_clicker.c @@ -7,7 +7,7 @@ #define TAG "HidMouseClicker" #define DEFAULT_CLICK_RATE 1 -#define MAXIMUM_CLICK_RATE 60 +#define MAXIMUM_CLICK_RATE 100 struct HidMouseClicker { View* view; @@ -34,7 +34,9 @@ static void hid_mouse_clicker_start_or_restart_timer(void* context) { HidMouseClickerModel * model, { furi_timer_start( - hid_mouse_clicker->timer, furi_kernel_get_tick_frequency() / model->rate); + hid_mouse_clicker->timer, + furi_kernel_get_tick_frequency() / + ((model->rate) ? model->rate : MAXIMUM_CLICK_RATE)); }, true); } @@ -75,7 +77,11 @@ static void hid_mouse_clicker_draw_callback(Canvas* canvas, void* context) { // Clicks/s char label[20]; - snprintf(label, sizeof(label), "%d clicks/s", model->rate); + if(model->rate) { + snprintf(label, sizeof(label), "%d clicks/s", model->rate); + } else { + snprintf(label, sizeof(label), "max clicks/s"); + } elements_multiline_text_aligned(canvas, 28, 37, AlignCenter, AlignBottom, label); canvas_draw_icon(canvas, 25, 20, &I_ButtonUp_7x4); @@ -139,7 +145,7 @@ static bool hid_mouse_clicker_input_callback(InputEvent* event, void* context) { consumed = true; break; case InputKeyDown: - if(model->rate > 1) { + if(model->rate > 0) { model->rate--; } rate_changed = true;