فهرست منبع

[FL-2975] Bug fixes and improvements: Furi, Input, Cli (#2004)

* Furi: configurable heap allocation tracking
* Furi: relax restriction in thread heap setter asserts, apply heap tracking setting on app start instead of thread allocation
* Furi: hide dangerous heap tracking levels in release build
* Input: fix non-working debounce
あく 3 سال پیش
والد
کامیت
90cefe7c71

+ 79 - 17
applications/services/cli/cli_commands.c

@@ -7,6 +7,7 @@
 #include <time.h>
 #include <notification/notification_messages.h>
 #include <loader/loader.h>
+#include <lib/toolbox/args.h>
 
 // Close to ISO, `date +'%Y-%m-%d %H:%M:%S %u'`
 #define CLI_DATE_FORMAT "%.4d-%.2d-%.2d %.2d:%.2d:%.2d %d"
@@ -192,35 +193,96 @@ void cli_command_log(Cli* cli, FuriString* args, void* context) {
     furi_stream_buffer_free(ring);
 }
 
-void cli_command_vibro(Cli* cli, FuriString* args, void* context) {
+void cli_command_sysctl_debug(Cli* cli, FuriString* args, void* context) {
     UNUSED(cli);
     UNUSED(context);
     if(!furi_string_cmp(args, "0")) {
-        NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
-        notification_message_block(notification, &sequence_reset_vibro);
-        furi_record_close(RECORD_NOTIFICATION);
+        furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug);
+        loader_update_menu();
+        printf("Debug disabled.");
     } else if(!furi_string_cmp(args, "1")) {
-        NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
-        notification_message_block(notification, &sequence_set_vibro_on);
-        furi_record_close(RECORD_NOTIFICATION);
+        furi_hal_rtc_set_flag(FuriHalRtcFlagDebug);
+        loader_update_menu();
+        printf("Debug enabled.");
     } else {
-        cli_print_usage("vibro", "<1|0>", furi_string_get_cstr(args));
+        cli_print_usage("sysctl debug", "<1|0>", furi_string_get_cstr(args));
     }
 }
 
-void cli_command_debug(Cli* cli, FuriString* args, void* context) {
+void cli_command_sysctl_heap_track(Cli* cli, FuriString* args, void* context) {
+    UNUSED(cli);
+    UNUSED(context);
+    if(!furi_string_cmp(args, "none")) {
+        furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackModeNone);
+        printf("Heap tracking disabled");
+    } else if(!furi_string_cmp(args, "main")) {
+        furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackModeMain);
+        printf("Heap tracking enabled for application main thread");
+#if FURI_DEBUG
+    } else if(!furi_string_cmp(args, "tree")) {
+        furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackModeTree);
+        printf("Heap tracking enabled for application main and child threads");
+    } else if(!furi_string_cmp(args, "all")) {
+        furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackModeAll);
+        printf("Heap tracking enabled for all threads");
+#endif
+    } else {
+        cli_print_usage("sysctl heap_track", "<none|main|tree|all>", furi_string_get_cstr(args));
+    }
+}
+
+void cli_command_sysctl_print_usage() {
+    printf("Usage:\r\n");
+    printf("sysctl <cmd> <args>\r\n");
+    printf("Cmd list:\r\n");
+
+    printf("\tdebug <0|1>\t - Enable or disable system debug\r\n");
+#if FURI_DEBUG
+    printf("\theap_track <none|main|tree|all>\t - Set heap allocation tracking mode\r\n");
+#else
+    printf("\theap_track <none|main>\t - Set heap allocation tracking mode\r\n");
+#endif
+}
+
+void cli_command_sysctl(Cli* cli, FuriString* args, void* context) {
+    FuriString* cmd;
+    cmd = furi_string_alloc();
+
+    do {
+        if(!args_read_string_and_trim(args, cmd)) {
+            cli_command_sysctl_print_usage();
+            break;
+        }
+
+        if(furi_string_cmp_str(cmd, "debug") == 0) {
+            cli_command_sysctl_debug(cli, args, context);
+            break;
+        }
+
+        if(furi_string_cmp_str(cmd, "heap_track") == 0) {
+            cli_command_sysctl_heap_track(cli, args, context);
+            break;
+        }
+
+        cli_command_sysctl_print_usage();
+    } while(false);
+
+    furi_string_free(cmd);
+}
+
+void cli_command_vibro(Cli* cli, FuriString* args, void* context) {
     UNUSED(cli);
     UNUSED(context);
     if(!furi_string_cmp(args, "0")) {
-        furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug);
-        loader_update_menu();
-        printf("Debug disabled.");
+        NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
+        notification_message_block(notification, &sequence_reset_vibro);
+        furi_record_close(RECORD_NOTIFICATION);
     } else if(!furi_string_cmp(args, "1")) {
-        furi_hal_rtc_set_flag(FuriHalRtcFlagDebug);
-        loader_update_menu();
-        printf("Debug enabled.");
+        NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
+        notification_message_block(notification, &sequence_set_vibro_on);
+        furi_record_close(RECORD_NOTIFICATION);
     } else {
-        cli_print_usage("debug", "<1|0>", furi_string_get_cstr(args));
+        cli_print_usage("vibro", "<1|0>", furi_string_get_cstr(args));
     }
 }
 
@@ -356,7 +418,7 @@ void cli_commands_init(Cli* cli) {
 
     cli_add_command(cli, "date", CliCommandFlagParallelSafe, cli_command_date, NULL);
     cli_add_command(cli, "log", CliCommandFlagParallelSafe, cli_command_log, NULL);
-    cli_add_command(cli, "debug", CliCommandFlagDefault, cli_command_debug, NULL);
+    cli_add_command(cli, "sysctl", CliCommandFlagDefault, cli_command_sysctl, NULL);
     cli_add_command(cli, "ps", CliCommandFlagParallelSafe, cli_command_ps, NULL);
     cli_add_command(cli, "free", CliCommandFlagParallelSafe, cli_command_free, NULL);
     cli_add_command(cli, "free_blocks", CliCommandFlagParallelSafe, cli_command_free_blocks, NULL);

+ 7 - 0
applications/services/desktop/scenes/desktop_scene_main.c

@@ -45,6 +45,13 @@ static void desktop_switch_to_app(Desktop* desktop, const FlipperApplication* fl
         return;
     }
 
+    FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode();
+    if(mode > FuriHalRtcHeapTrackModeNone) {
+        furi_thread_enable_heap_trace(desktop->scene_thread);
+    } else {
+        furi_thread_disable_heap_trace(desktop->scene_thread);
+    }
+
     furi_thread_set_name(desktop->scene_thread, flipper_app->name);
     furi_thread_set_stack_size(desktop->scene_thread, flipper_app->stack_size);
     furi_thread_set_callback(desktop->scene_thread, flipper_app->app);

+ 19 - 1
applications/services/input/input.c

@@ -1,5 +1,7 @@
 #include "input_i.h"
 
+// #define INPUT_DEBUG
+
 #define GPIO_Read(input_pin) (furi_hal_gpio_read(input_pin.pin->gpio) ^ (input_pin.pin->inverted))
 
 static Input* input = NULL;
@@ -72,6 +74,10 @@ int32_t input_srv(void* p) {
     input->event_pubsub = furi_pubsub_alloc();
     furi_record_create(RECORD_INPUT_EVENTS, input->event_pubsub);
 
+#if INPUT_DEBUG
+    furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeOutputPushPull);
+#endif
+
 #ifdef SRV_CLI
     input->cli = furi_record_open(RECORD_CLI);
     if(input->cli) {
@@ -95,10 +101,16 @@ int32_t input_srv(void* p) {
         bool is_changing = false;
         for(size_t i = 0; i < input_pins_count; i++) {
             bool state = GPIO_Read(input->pin_states[i]);
+            if(state) {
+                if(input->pin_states[i].debounce < INPUT_DEBOUNCE_TICKS)
+                    input->pin_states[i].debounce += 1;
+            } else {
+                if(input->pin_states[i].debounce > 0) input->pin_states[i].debounce -= 1;
+            }
+
             if(input->pin_states[i].debounce > 0 &&
                input->pin_states[i].debounce < INPUT_DEBOUNCE_TICKS) {
                 is_changing = true;
-                input->pin_states[i].debounce += (state ? 1 : -1);
             } else if(input->pin_states[i].state != state) {
                 input->pin_states[i].state = state;
 
@@ -129,8 +141,14 @@ int32_t input_srv(void* p) {
         }
 
         if(is_changing) {
+#if INPUT_DEBUG
+            furi_hal_gpio_write(&gpio_ext_pa4, 1);
+#endif
             furi_delay_tick(1);
         } else {
+#if INPUT_DEBUG
+            furi_hal_gpio_write(&gpio_ext_pa4, 0);
+#endif
             furi_thread_flags_wait(INPUT_THREAD_FLAG_ISR, FuriFlagWaitAny, FuriWaitForever);
         }
     }

+ 8 - 1
applications/services/loader/loader.c

@@ -21,6 +21,13 @@ static bool
 
     FURI_LOG_I(TAG, "Starting: %s", loader_instance->application->name);
 
+    FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode();
+    if(mode > FuriHalRtcHeapTrackModeNone) {
+        furi_thread_enable_heap_trace(loader_instance->application_thread);
+    } else {
+        furi_thread_disable_heap_trace(loader_instance->application_thread);
+    }
+
     furi_thread_set_name(loader_instance->application_thread, loader_instance->application->name);
     furi_thread_set_stack_size(
         loader_instance->application_thread, loader_instance->application->stack_size);
@@ -306,7 +313,7 @@ static Loader* loader_alloc() {
     Loader* instance = malloc(sizeof(Loader));
 
     instance->application_thread = furi_thread_alloc();
-    furi_thread_enable_heap_trace(instance->application_thread);
+
     furi_thread_set_state_context(instance->application_thread, instance);
     furi_thread_set_state_callback(instance->application_thread, loader_thread_state_callback);
 

+ 37 - 0
applications/settings/system/system_settings.c

@@ -45,6 +45,31 @@ static void debug_changed(VariableItem* item) {
     loader_update_menu();
 }
 
+const char* const heap_trace_mode_text[] = {
+    "None",
+    "Main",
+#if FURI_DEBUG
+    "Tree",
+    "All",
+#endif
+};
+
+const uint32_t heap_trace_mode_value[] = {
+    FuriHalRtcHeapTrackModeNone,
+    FuriHalRtcHeapTrackModeMain,
+#if FURI_DEBUG
+    FuriHalRtcHeapTrackModeTree,
+    FuriHalRtcHeapTrackModeAll,
+#endif
+};
+
+static void heap_trace_mode_changed(VariableItem* item) {
+    // SystemSettings* app = variable_item_get_context(item);
+    uint8_t index = variable_item_get_current_value_index(item);
+    variable_item_set_current_value_text(item, heap_trace_mode_text[index]);
+    furi_hal_rtc_set_heap_track_mode(heap_trace_mode_value[index]);
+}
+
 static uint32_t system_settings_exit(void* context) {
     UNUSED(context);
     return VIEW_NONE;
@@ -79,6 +104,18 @@ SystemSettings* system_settings_alloc() {
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_text(item, debug_text[value_index]);
 
+    item = variable_item_list_add(
+        app->var_item_list,
+        "Heap Trace",
+        COUNT_OF(heap_trace_mode_text),
+        heap_trace_mode_changed,
+        app);
+    value_index = value_index_uint32(
+        furi_hal_rtc_get_heap_track_mode(), heap_trace_mode_value, COUNT_OF(heap_trace_mode_text));
+    furi_hal_rtc_set_heap_track_mode(heap_trace_mode_value[value_index]);
+    variable_item_set_current_value_index(item, value_index);
+    variable_item_set_current_value_text(item, heap_trace_mode_text[value_index]);
+
     view_set_previous_callback(
         variable_item_list_get_view(app->var_item_list), system_settings_exit);
     view_dispatcher_add_view(

+ 3 - 1
firmware/targets/f7/api_symbols.csv

@@ -1,5 +1,5 @@
 entry,status,name,type,params
-Version,+,7.4,,
+Version,+,7.5,,
 Header,+,applications/services/bt/bt_service/bt.h,,
 Header,+,applications/services/cli/cli.h,,
 Header,+,applications/services/cli/cli_vcp.h,,
@@ -1260,6 +1260,7 @@ Function,+,furi_hal_rtc_deinit_early,void,
 Function,+,furi_hal_rtc_get_boot_mode,FuriHalRtcBootMode,
 Function,+,furi_hal_rtc_get_datetime,void,FuriHalRtcDateTime*
 Function,+,furi_hal_rtc_get_fault_data,uint32_t,
+Function,+,furi_hal_rtc_get_heap_track_mode,FuriHalRtcHeapTrackMode,
 Function,+,furi_hal_rtc_get_log_level,uint8_t,
 Function,+,furi_hal_rtc_get_pin_fails,uint32_t,
 Function,+,furi_hal_rtc_get_register,uint32_t,FuriHalRtcRegister
@@ -1272,6 +1273,7 @@ Function,+,furi_hal_rtc_set_boot_mode,void,FuriHalRtcBootMode
 Function,+,furi_hal_rtc_set_datetime,void,FuriHalRtcDateTime*
 Function,+,furi_hal_rtc_set_fault_data,void,uint32_t
 Function,+,furi_hal_rtc_set_flag,void,FuriHalRtcFlag
+Function,+,furi_hal_rtc_set_heap_track_mode,void,FuriHalRtcHeapTrackMode
 Function,+,furi_hal_rtc_set_log_level,void,uint8_t
 Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t
 Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t"

+ 1 - 1
firmware/targets/f7/furi_hal/furi_hal_resources.h

@@ -10,7 +10,7 @@ extern "C" {
 #endif
 
 /* Input Related Constants */
-#define INPUT_DEBOUNCE_TICKS 30
+#define INPUT_DEBOUNCE_TICKS 4
 
 /* Input Keys */
 typedef enum {

+ 15 - 1
firmware/targets/f7/furi_hal/furi_hal_rtc.c

@@ -30,7 +30,8 @@ typedef struct {
     uint8_t log_reserved : 4;
     uint8_t flags;
     uint8_t boot_mode : 4;
-    uint16_t reserved : 12;
+    uint8_t heap_track_mode : 2;
+    uint16_t reserved : 10;
 } DeveloperReg;
 
 _Static_assert(sizeof(DeveloperReg) == 4, "DeveloperReg size mismatch");
@@ -224,6 +225,19 @@ FuriHalRtcBootMode furi_hal_rtc_get_boot_mode() {
     return (FuriHalRtcBootMode)data->boot_mode;
 }
 
+void furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackMode mode) {
+    uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
+    DeveloperReg* data = (DeveloperReg*)&data_reg;
+    data->heap_track_mode = mode;
+    furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
+}
+
+FuriHalRtcHeapTrackMode furi_hal_rtc_get_heap_track_mode() {
+    uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
+    DeveloperReg* data = (DeveloperReg*)&data_reg;
+    return (FuriHalRtcHeapTrackMode)data->heap_track_mode;
+}
+
 void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime) {
     furi_assert(datetime);
 

+ 11 - 0
firmware/targets/furi_hal_include/furi_hal_rtc.h

@@ -39,6 +39,13 @@ typedef enum {
     FuriHalRtcBootModePostUpdate, /**< Boot to Update, post update */
 } FuriHalRtcBootMode;
 
+typedef enum {
+    FuriHalRtcHeapTrackModeNone = 0, /**< Disable allocation tracking */
+    FuriHalRtcHeapTrackModeMain, /**< Enable allocation tracking for main application thread */
+    FuriHalRtcHeapTrackModeTree, /**< Enable allocation tracking for main and children application threads */
+    FuriHalRtcHeapTrackModeAll, /**< Enable allocation tracking for all threads */
+} FuriHalRtcHeapTrackMode;
+
 typedef enum {
     FuriHalRtcRegisterHeader, /**< RTC structure header */
     FuriHalRtcRegisterSystem, /**< Various system bits */
@@ -79,6 +86,10 @@ void furi_hal_rtc_set_boot_mode(FuriHalRtcBootMode mode);
 
 FuriHalRtcBootMode furi_hal_rtc_get_boot_mode();
 
+void furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackMode mode);
+
+FuriHalRtcHeapTrackMode furi_hal_rtc_get_heap_track_mode();
+
 void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime);
 
 void furi_hal_rtc_get_datetime(FuriHalRtcDateTime* datetime);

+ 6 - 3
furi/core/thread.c

@@ -122,9 +122,14 @@ FuriThread* furi_thread_alloc() {
     thread->output.buffer = furi_string_alloc();
     thread->is_service = false;
 
-    if(furi_thread_get_current_id()) {
+    FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode();
+    if(mode == FuriHalRtcHeapTrackModeAll) {
+        thread->heap_trace_enabled = true;
+    } else if(mode == FuriHalRtcHeapTrackModeTree && furi_thread_get_current_id()) {
         FuriThread* parent = pvTaskGetThreadLocalStoragePointer(NULL, 0);
         if(parent) thread->heap_trace_enabled = parent->heap_trace_enabled;
+    } else {
+        thread->heap_trace_enabled = false;
     }
 
     return thread;
@@ -243,14 +248,12 @@ FuriThreadId furi_thread_get_id(FuriThread* thread) {
 void furi_thread_enable_heap_trace(FuriThread* thread) {
     furi_assert(thread);
     furi_assert(thread->state == FuriThreadStateStopped);
-    furi_assert(thread->heap_trace_enabled == false);
     thread->heap_trace_enabled = true;
 }
 
 void furi_thread_disable_heap_trace(FuriThread* thread) {
     furi_assert(thread);
     furi_assert(thread->state == FuriThreadStateStopped);
-    furi_assert(thread->heap_trace_enabled == true);
     thread->heap_trace_enabled = false;
 }