Ray 1 ano atrás
pai
commit
e04021a828
5 arquivos alterados com 124 adições e 205 exclusões
  1. 109 75
      cli_control.c
  2. 4 4
      cli_control.h
  3. 11 12
      cligui_main.c
  4. 0 2
      cligui_main_i.h
  5. 0 112
      internal_defs.h

+ 109 - 75
cli_control.c

@@ -1,116 +1,150 @@
 #include "cli_control.h"
 
+#include <FreeRTOS.h>
 #include <cli/cli.h>
 #include <cli/cli_i.h>
 #include <cli/cli_vcp.h>
-#include "cligui_main_i.h"
-#include <FreeRTOS.h>
+#include <loader/loader.h>
+#include <loader/loader_i.h>
 
-volatile bool gotCallbackSet = false;
+FuriStreamBuffer* cli_tx_stream = NULL;
+FuriStreamBuffer* cli_rx_stream = NULL;
+
+static volatile bool restore_tx_stdout = false;
 
-FuriStreamBuffer* tx_stream;
-FuriStreamBuffer* rx_stream;
-static FuriThread* volatile cliThread = NULL;
-static FuriThread* prev_appthread = NULL;
-static void tx_handler_stdout(const char* buffer, size_t size) {
-    furi_stream_buffer_send(tx_stream, buffer, size, FuriWaitForever);
-}
 static void tx_handler(const uint8_t* buffer, size_t size) {
-    furi_thread_set_stdout_callback(tx_handler_stdout);
-    cliThread = furi_thread_get_current();
-    furi_stream_buffer_send(tx_stream, buffer, size, FuriWaitForever);
+    furi_stream_buffer_send(cli_tx_stream, buffer, size, FuriWaitForever);
 }
+
+static void tx_handler_stdout(const char* buffer, size_t size) {
+    tx_handler((const uint8_t*)buffer, size);
+}
+
 static size_t real_rx_handler(uint8_t* buffer, size_t size, uint32_t timeout) {
     size_t rx_cnt = 0;
-    while(size > 0) {
+    while (size > 0) {
         size_t batch_size = size;
-        if(batch_size > 128) batch_size = 128;
-        size_t len = furi_stream_buffer_receive(rx_stream, buffer, batch_size, timeout);
-        if(len == 0) break;
+        if (batch_size > 128)
+            batch_size = 128;
+        size_t len = furi_stream_buffer_receive(cli_rx_stream, buffer, batch_size, timeout);
+        if (len == 0)
+            break;
         size -= len;
         buffer += len;
         rx_cnt += len;
     }
+    if (restore_tx_stdout) {
+        furi_thread_set_stdout_callback(cli_vcp.tx_stdout);
+    } else {
+        furi_thread_set_stdout_callback(tx_handler_stdout);
+    }
     return rx_cnt;
 }
 
-static CliCommand_internal* getInternalCliCommand(Cli* cli, const char* name) {
-    FuriString* target_command = furi_string_alloc();
-    furi_string_set_str(target_command, name);
-    CliCommand_internal* command =
-        CliCommandTree_internal_get(((Cli_internal*)cli)->commands, target_command);
-    furi_string_free(target_command);
-    return command;
-}
+static CliSession* session;
 
-static void session_init(void) {
-}
+static void session_init(void) {}
 static void session_deinit(void) {
+    free(session);
+    session = NULL;
 }
+
 static bool session_connected(void) {
     return true;
 }
-static CliSession session;
-void latch_tx_handler() {
+
+void clicontrol_hijack(size_t tx_size, size_t rx_size) {
+    if (cli_rx_stream != NULL && cli_tx_stream != NULL) {
+        return;
+    }
+
     Cli* global_cli = furi_record_open(RECORD_CLI);
 
-    CliCommand_internal* help_command = getInternalCliCommand(global_cli, "help");
-    cliThread = help_command->context;
+    cli_rx_stream = furi_stream_buffer_alloc(rx_size, 1);
+    cli_tx_stream = furi_stream_buffer_alloc(tx_size, 1);
 
-    furi_thread_set_stdout_callback(tx_handler_stdout);
-    if(cliThread != NULL) {
-        ((FuriThread_internal*)cliThread)->output.write_callback = &tx_handler_stdout;
-    }
+    session = (CliSession*)malloc(sizeof(CliSession));
+    session->tx = &tx_handler;
+    session->rx = &real_rx_handler;
+    session->tx_stdout = &tx_handler_stdout;
+    session->init = &session_init;
+    session->deinit = &session_deinit;
+    session->is_connected = &session_connected;
 
-    rx_stream = furi_stream_buffer_alloc(128, 1);
-    tx_stream = furi_stream_buffer_alloc(128, 1);
+    CliCommandTree_it_t cmd_iterator;
+    for (CliCommandTree_it(cmd_iterator, global_cli->commands);
+         !CliCommandTree_end_p(cmd_iterator);
+         CliCommandTree_next(cmd_iterator)) {
+        CliCommand* t = CliCommandTree_cref(cmd_iterator)->value_ptr;
+        // Move CliCommandFlagParallelSafe to another bit
+        t->flags ^= ((t->flags & (CliCommandFlagParallelSafe << 8)) ^
+                     ((t->flags & CliCommandFlagParallelSafe) << 8));
+        // Set parallel safe
+        t->flags |= CliCommandFlagParallelSafe;
+    }
 
-    session.tx = &tx_handler;
-    session.rx = &real_rx_handler;
-    session.tx_stdout = &tx_handler_stdout;
-    session.init = &session_init;
-    session.deinit = &session_deinit;
-    session.is_connected = &session_connected;
+    // Session switcharooney
+    FuriThreadStdoutWriteCallback prev_stdout = furi_thread_get_stdout_callback();
     cli_session_close(global_cli);
-    cli_session_open(global_cli, &session);
-    // Unlock loader-lock
-    Loader* loader = furi_record_open(RECORD_LOADER);
-    Loader_internal* loader_i = (Loader_internal*)loader;
-    prev_appthread = loader_i->app.thread;
-    loader_i->app.thread = NULL;
-    furi_record_close(RECORD_LOADER);
+    restore_tx_stdout = false;
+    cli_session_open(global_cli, session);
+    furi_thread_set_stdout_callback(prev_stdout);
+
     furi_record_close(RECORD_CLI);
 }
-void unlatch_tx_handler(bool persist) {
-    Cli* global_cli = furi_record_open(RECORD_CLI);
-    // Stash cliThread if not null
-    if(cliThread != NULL) {
-        CliCommand_internal* help_command = getInternalCliCommand(global_cli, "help");
-        help_command->context = cliThread;
+
+void clicontrol_unhijack(bool persist) {
+    if (cli_rx_stream == NULL && cli_tx_stream == NULL) {
+        return;
     }
-    // Switch to new session
-    if(persist) {
-        // Use dummy debug firmware function as is_connected
+
+    // Consume remaining tx data
+    if (furi_stream_buffer_bytes_available(cli_tx_stream) > 0) {
+        char sink = 0;
+        while (!furi_stream_buffer_is_empty(cli_tx_stream)) {
+            furi_stream_buffer_receive(cli_tx_stream, &sink, 1, FuriWaitForever);
+        }
+    }
+
+    Cli* global_cli = furi_record_open(RECORD_CLI);
+
+    if (persist) {
+        // Don't trigger a terminal reset as the session switches
         cli_vcp.is_connected = &furi_hal_version_do_i_belong_here;
     } else {
-        // Send CTRL-C
+        // Send CTRL-C a few times
         char eot = 0x03;
-        furi_stream_buffer_send(rx_stream, &eot, 1, FuriWaitForever);
+        furi_stream_buffer_send(cli_rx_stream, &eot, 1, FuriWaitForever);
+        furi_stream_buffer_send(cli_rx_stream, &eot, 1, FuriWaitForever);
+        furi_stream_buffer_send(cli_rx_stream, &eot, 1, FuriWaitForever);
     }
+
+    // Restore command flags
+    CliCommandTree_it_t cmd_iterator;
+    for (CliCommandTree_it(cmd_iterator, global_cli->commands);
+         !CliCommandTree_end_p(cmd_iterator);
+         CliCommandTree_next(cmd_iterator)) {
+        CliCommand* t = CliCommandTree_cref(cmd_iterator)->value_ptr;
+        t->flags ^= (((t->flags & CliCommandFlagParallelSafe) >> 8) ^
+                     ((t->flags & (CliCommandFlagParallelSafe << 8)) >> 8));
+    }
+
+    restore_tx_stdout = true;  // Ready for next rx call
+
+    // Session switcharooney again
+    FuriThreadStdoutWriteCallback prev_stdout = furi_thread_get_stdout_callback();
+    cli_session_close(global_cli);
     cli_session_open(global_cli, &cli_vcp);
+    furi_thread_set_stdout_callback(prev_stdout);
     furi_record_close(RECORD_CLI);
-    // Unblock waiting rx handler
-    furi_stream_buffer_send(rx_stream, "_", 1, FuriWaitForever);
-    // Reconfigure stdout_callback to cli_vcp
-    if(cliThread != NULL) {
-        ((FuriThread_internal*)cliThread)->output.write_callback = cli_vcp.tx_stdout;
-    }
-    // At this point, all cli_vcp functions should be back.
-    furi_stream_buffer_free(rx_stream);
-    furi_stream_buffer_free(tx_stream);
-    // Re-lock loader (to avoid crash on automatic unlock)
-    Loader* loader = furi_record_open(RECORD_LOADER);
-    Loader_internal* loader_i = (Loader_internal*)loader;
-    loader_i->app.thread = prev_appthread;
-    furi_record_close(RECORD_LOADER);
+
+    // Unblock waiting rx handler, restore old cli_vcp.tx_stdout
+    furi_stream_buffer_send(cli_rx_stream, "_", 1, FuriWaitForever);
+
+    // At this point, all cli_vcp functions should be restored.
+
+    furi_stream_buffer_free(cli_rx_stream);
+    furi_stream_buffer_free(cli_tx_stream);
+    cli_rx_stream = NULL;
+    cli_tx_stream = NULL;
 }

+ 4 - 4
cli_control.h

@@ -2,7 +2,7 @@
 
 #include <furi.h>
 #include <furi_hal.h>
-extern void latch_tx_handler();
-extern void unlatch_tx_handler(bool persist);
-extern FuriStreamBuffer* tx_stream;
-extern FuriStreamBuffer* rx_stream;
+extern void clicontrol_hijack(size_t tx_size, size_t rx_size);
+extern void clicontrol_unhijack(bool persist);
+extern FuriStreamBuffer* cli_tx_stream;
+extern FuriStreamBuffer* cli_rx_stream;

+ 11 - 12
cligui_main.c

@@ -41,9 +41,9 @@ static void cligui_tick_event_cb(void* context) {
     UNUSED(app);
 }
 
-ViewPortInputCallback prev_input_callback;
 volatile bool persistent_exit = false;
-static void input_callback_wrapper(InputEvent* event, void* context) {
+static void input_callback(const void* event_ptr, void* context) {
+    InputEvent* event = (InputEvent*)event_ptr;
     CliguiApp* app = context;
     if(event->type == InputTypeLong && event->key == InputKeyBack) {
         persistent_exit = false;
@@ -60,7 +60,6 @@ static void input_callback_wrapper(InputEvent* event, void* context) {
     } else {
         console_output_input_handler(app, event);
     }
-    prev_input_callback(event, app->view_dispatcher);
 }
 
 int32_t cligui_main(void* p) {
@@ -68,17 +67,14 @@ int32_t cligui_main(void* p) {
     CliguiApp* cligui = malloc(sizeof(CliguiApp));
     cligui->data = malloc(sizeof(CliguiData));
 
-    latch_tx_handler();
-    cligui->data->streams.app_tx = rx_stream;
-    cligui->data->streams.app_rx = tx_stream;
+    clicontrol_hijack(512, 512);
+    cligui->data->streams.app_tx = cli_rx_stream;
+    cligui->data->streams.app_rx = cli_tx_stream;
 
     cligui->gui = furi_record_open(RECORD_GUI);
     cligui->view_dispatcher = view_dispatcher_alloc();
-    cligui->view_dispatcher_i = (ViewDispatcher_internal*)(cligui->view_dispatcher);
-    prev_input_callback =
-        ((ViewPort_internal*)cligui->view_dispatcher_i->view_port)->input_callback;
-    view_port_input_callback_set(
-        cligui->view_dispatcher_i->view_port, input_callback_wrapper, cligui);
+    FuriPubSub* input_events = furi_record_open(RECORD_INPUT_EVENTS);
+    FuriPubSubSubscription* input_events_sub = furi_pubsub_subscribe(input_events, input_callback, (void*)cligui);
     view_dispatcher_enable_queue(cligui->view_dispatcher);
     view_dispatcher_set_event_callback_context(cligui->view_dispatcher, cligui);
     view_dispatcher_set_custom_event_callback(cligui->view_dispatcher, cligui_custom_event_cb);
@@ -122,9 +118,12 @@ int32_t cligui_main(void* p) {
     text_input_free(cligui->text_input);
     view_dispatcher_free(cligui->view_dispatcher);
 
-    unlatch_tx_handler(persistent_exit);
+    clicontrol_unhijack(persistent_exit);
+
+    furi_pubsub_unsubscribe(input_events, input_events_sub);
 
     furi_record_close(RECORD_GUI);
+    furi_record_close(RECORD_INPUT_EVENTS);
 
     free(cligui->data);
     free(cligui);

+ 0 - 2
cligui_main_i.h

@@ -11,7 +11,6 @@
 #include <gui/modules/text_input.h>
 #include <m-dict.h>
 #include <loader/loader.h>
-#include "internal_defs.h"
 
 #define TEXT_BOX_STORE_SIZE (4096)
 #define TEXT_INPUT_STORE_SIZE (512)
@@ -37,5 +36,4 @@ typedef struct {
     char text_input_store[TEXT_INPUT_STORE_SIZE + 1];
     TextInput* text_input;
     ViewDispatcher* view_dispatcher;
-    ViewDispatcher_internal* view_dispatcher_i;
 } CliguiApp;

+ 0 - 112
internal_defs.h

@@ -1,112 +0,0 @@
-#pragma once
-#include <furi.h>
-#include <furi_hal.h>
-#include <m-dict.h>
-#include <m-bptree.h>
-#include <m-array.h>
-#include <cli/cli.h>
-
-typedef struct {
-    FuriThreadStdoutWriteCallback write_callback;
-    FuriString* buffer;
-} FuriThreadStdout_internal;
-
-typedef struct {
-    bool is_service;
-    FuriThreadState state;
-    int32_t ret;
-
-    FuriThreadCallback callback;
-    void* context;
-
-    FuriThreadStateCallback state_callback;
-    void* state_context;
-
-    char* name;
-    configSTACK_DEPTH_TYPE stack_size;
-    FuriThreadPriority priority;
-
-    TaskHandle_t task_handle;
-    bool heap_trace_enabled;
-    size_t heap_size;
-
-    FuriThreadStdout_internal output;
-} FuriThread_internal;
-
-DICT_DEF2(ViewDict, uint32_t, M_DEFAULT_OPLIST, View*, M_PTR_OPLIST)
-typedef struct {
-    FuriMessageQueue* queue;
-    Gui* gui;
-    ViewPort* view_port;
-    ViewDict_t views;
-
-    View* current_view;
-
-    View* ongoing_input_view;
-    uint8_t ongoing_input;
-
-    ViewDispatcherCustomEventCallback custom_event_callback;
-    ViewDispatcherNavigationEventCallback navigation_event_callback;
-    ViewDispatcherTickEventCallback tick_event_callback;
-    uint32_t tick_period;
-    void* event_context;
-} ViewDispatcher_internal;
-
-typedef struct {
-    Gui* gui;
-    bool is_enabled;
-    ViewPortOrientation orientation;
-
-    uint8_t width;
-    uint8_t height;
-
-    ViewPortDrawCallback draw_callback;
-    void* draw_callback_context;
-
-    ViewPortInputCallback input_callback;
-    void* input_callback_context;
-} ViewPort_internal;
-
-typedef struct {
-    char* args;
-    FuriThread* thread;
-    bool insomniac;
-    void* fap;
-} LoaderAppData_internal;
-
-typedef struct {
-    void* pubsub;
-    void* queue;
-    void* loader_menu;
-    void* loader_applications;
-    LoaderAppData_internal app;
-} Loader_internal;
-
-
-typedef struct {
-    CliCallback callback;
-    void* context;
-    uint32_t flags;
-} CliCommand_internal;
-
-#define CLI_COMMANDS_TREE_RANK 4
-BPTREE_DEF2(
-    CliCommandTree_internal,
-    CLI_COMMANDS_TREE_RANK,
-    FuriString*,
-    FURI_STRING_OPLIST,
-    CliCommand_internal,
-    M_POD_OPLIST)
-
-#define M_OPL_CliCommandTree_internal_t() BPTREE_OPLIST(CliCommandTree_internal, M_POD_OPLIST)
-
-typedef struct {
-    CliCommandTree_internal_t commands;
-    void* mutex;
-    void* idle_sem;
-    void* last_line;
-    void* line;
-    void* session;
-
-    size_t cursor_position;
-} Cli_internal;