Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
ranchordo committed Sep 22, 2024
1 parent aa42c1a commit e04021a
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 205 deletions.
184 changes: 109 additions & 75 deletions cli_control.c
Original file line number Diff line number Diff line change
@@ -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;
}
8 changes: 4 additions & 4 deletions cli_control.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
23 changes: 11 additions & 12 deletions cligui_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -60,25 +60,21 @@ 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) {
UNUSED(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);
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 0 additions & 2 deletions cligui_main_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
Loading

0 comments on commit e04021a

Please sign in to comment.