Skip to content

Commit e04021a

Browse files
committed
fixes
1 parent aa42c1a commit e04021a

File tree

5 files changed

+124
-205
lines changed

5 files changed

+124
-205
lines changed

cli_control.c

Lines changed: 109 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,150 @@
11
#include "cli_control.h"
22

3+
#include <FreeRTOS.h>
34
#include <cli/cli.h>
45
#include <cli/cli_i.h>
56
#include <cli/cli_vcp.h>
6-
#include "cligui_main_i.h"
7-
#include <FreeRTOS.h>
7+
#include <loader/loader.h>
8+
#include <loader/loader_i.h>
89

9-
volatile bool gotCallbackSet = false;
10+
FuriStreamBuffer* cli_tx_stream = NULL;
11+
FuriStreamBuffer* cli_rx_stream = NULL;
12+
13+
static volatile bool restore_tx_stdout = false;
1014

11-
FuriStreamBuffer* tx_stream;
12-
FuriStreamBuffer* rx_stream;
13-
static FuriThread* volatile cliThread = NULL;
14-
static FuriThread* prev_appthread = NULL;
15-
static void tx_handler_stdout(const char* buffer, size_t size) {
16-
furi_stream_buffer_send(tx_stream, buffer, size, FuriWaitForever);
17-
}
1815
static void tx_handler(const uint8_t* buffer, size_t size) {
19-
furi_thread_set_stdout_callback(tx_handler_stdout);
20-
cliThread = furi_thread_get_current();
21-
furi_stream_buffer_send(tx_stream, buffer, size, FuriWaitForever);
16+
furi_stream_buffer_send(cli_tx_stream, buffer, size, FuriWaitForever);
2217
}
18+
19+
static void tx_handler_stdout(const char* buffer, size_t size) {
20+
tx_handler((const uint8_t*)buffer, size);
21+
}
22+
2323
static size_t real_rx_handler(uint8_t* buffer, size_t size, uint32_t timeout) {
2424
size_t rx_cnt = 0;
25-
while(size > 0) {
25+
while (size > 0) {
2626
size_t batch_size = size;
27-
if(batch_size > 128) batch_size = 128;
28-
size_t len = furi_stream_buffer_receive(rx_stream, buffer, batch_size, timeout);
29-
if(len == 0) break;
27+
if (batch_size > 128)
28+
batch_size = 128;
29+
size_t len = furi_stream_buffer_receive(cli_rx_stream, buffer, batch_size, timeout);
30+
if (len == 0)
31+
break;
3032
size -= len;
3133
buffer += len;
3234
rx_cnt += len;
3335
}
36+
if (restore_tx_stdout) {
37+
furi_thread_set_stdout_callback(cli_vcp.tx_stdout);
38+
} else {
39+
furi_thread_set_stdout_callback(tx_handler_stdout);
40+
}
3441
return rx_cnt;
3542
}
3643

37-
static CliCommand_internal* getInternalCliCommand(Cli* cli, const char* name) {
38-
FuriString* target_command = furi_string_alloc();
39-
furi_string_set_str(target_command, name);
40-
CliCommand_internal* command =
41-
CliCommandTree_internal_get(((Cli_internal*)cli)->commands, target_command);
42-
furi_string_free(target_command);
43-
return command;
44-
}
44+
static CliSession* session;
4545

46-
static void session_init(void) {
47-
}
46+
static void session_init(void) {}
4847
static void session_deinit(void) {
48+
free(session);
49+
session = NULL;
4950
}
51+
5052
static bool session_connected(void) {
5153
return true;
5254
}
53-
static CliSession session;
54-
void latch_tx_handler() {
55+
56+
void clicontrol_hijack(size_t tx_size, size_t rx_size) {
57+
if (cli_rx_stream != NULL && cli_tx_stream != NULL) {
58+
return;
59+
}
60+
5561
Cli* global_cli = furi_record_open(RECORD_CLI);
5662

57-
CliCommand_internal* help_command = getInternalCliCommand(global_cli, "help");
58-
cliThread = help_command->context;
63+
cli_rx_stream = furi_stream_buffer_alloc(rx_size, 1);
64+
cli_tx_stream = furi_stream_buffer_alloc(tx_size, 1);
5965

60-
furi_thread_set_stdout_callback(tx_handler_stdout);
61-
if(cliThread != NULL) {
62-
((FuriThread_internal*)cliThread)->output.write_callback = &tx_handler_stdout;
63-
}
66+
session = (CliSession*)malloc(sizeof(CliSession));
67+
session->tx = &tx_handler;
68+
session->rx = &real_rx_handler;
69+
session->tx_stdout = &tx_handler_stdout;
70+
session->init = &session_init;
71+
session->deinit = &session_deinit;
72+
session->is_connected = &session_connected;
6473

65-
rx_stream = furi_stream_buffer_alloc(128, 1);
66-
tx_stream = furi_stream_buffer_alloc(128, 1);
74+
CliCommandTree_it_t cmd_iterator;
75+
for (CliCommandTree_it(cmd_iterator, global_cli->commands);
76+
!CliCommandTree_end_p(cmd_iterator);
77+
CliCommandTree_next(cmd_iterator)) {
78+
CliCommand* t = CliCommandTree_cref(cmd_iterator)->value_ptr;
79+
// Move CliCommandFlagParallelSafe to another bit
80+
t->flags ^= ((t->flags & (CliCommandFlagParallelSafe << 8)) ^
81+
((t->flags & CliCommandFlagParallelSafe) << 8));
82+
// Set parallel safe
83+
t->flags |= CliCommandFlagParallelSafe;
84+
}
6785

68-
session.tx = &tx_handler;
69-
session.rx = &real_rx_handler;
70-
session.tx_stdout = &tx_handler_stdout;
71-
session.init = &session_init;
72-
session.deinit = &session_deinit;
73-
session.is_connected = &session_connected;
86+
// Session switcharooney
87+
FuriThreadStdoutWriteCallback prev_stdout = furi_thread_get_stdout_callback();
7488
cli_session_close(global_cli);
75-
cli_session_open(global_cli, &session);
76-
// Unlock loader-lock
77-
Loader* loader = furi_record_open(RECORD_LOADER);
78-
Loader_internal* loader_i = (Loader_internal*)loader;
79-
prev_appthread = loader_i->app.thread;
80-
loader_i->app.thread = NULL;
81-
furi_record_close(RECORD_LOADER);
89+
restore_tx_stdout = false;
90+
cli_session_open(global_cli, session);
91+
furi_thread_set_stdout_callback(prev_stdout);
92+
8293
furi_record_close(RECORD_CLI);
8394
}
84-
void unlatch_tx_handler(bool persist) {
85-
Cli* global_cli = furi_record_open(RECORD_CLI);
86-
// Stash cliThread if not null
87-
if(cliThread != NULL) {
88-
CliCommand_internal* help_command = getInternalCliCommand(global_cli, "help");
89-
help_command->context = cliThread;
95+
96+
void clicontrol_unhijack(bool persist) {
97+
if (cli_rx_stream == NULL && cli_tx_stream == NULL) {
98+
return;
9099
}
91-
// Switch to new session
92-
if(persist) {
93-
// Use dummy debug firmware function as is_connected
100+
101+
// Consume remaining tx data
102+
if (furi_stream_buffer_bytes_available(cli_tx_stream) > 0) {
103+
char sink = 0;
104+
while (!furi_stream_buffer_is_empty(cli_tx_stream)) {
105+
furi_stream_buffer_receive(cli_tx_stream, &sink, 1, FuriWaitForever);
106+
}
107+
}
108+
109+
Cli* global_cli = furi_record_open(RECORD_CLI);
110+
111+
if (persist) {
112+
// Don't trigger a terminal reset as the session switches
94113
cli_vcp.is_connected = &furi_hal_version_do_i_belong_here;
95114
} else {
96-
// Send CTRL-C
115+
// Send CTRL-C a few times
97116
char eot = 0x03;
98-
furi_stream_buffer_send(rx_stream, &eot, 1, FuriWaitForever);
117+
furi_stream_buffer_send(cli_rx_stream, &eot, 1, FuriWaitForever);
118+
furi_stream_buffer_send(cli_rx_stream, &eot, 1, FuriWaitForever);
119+
furi_stream_buffer_send(cli_rx_stream, &eot, 1, FuriWaitForever);
99120
}
121+
122+
// Restore command flags
123+
CliCommandTree_it_t cmd_iterator;
124+
for (CliCommandTree_it(cmd_iterator, global_cli->commands);
125+
!CliCommandTree_end_p(cmd_iterator);
126+
CliCommandTree_next(cmd_iterator)) {
127+
CliCommand* t = CliCommandTree_cref(cmd_iterator)->value_ptr;
128+
t->flags ^= (((t->flags & CliCommandFlagParallelSafe) >> 8) ^
129+
((t->flags & (CliCommandFlagParallelSafe << 8)) >> 8));
130+
}
131+
132+
restore_tx_stdout = true; // Ready for next rx call
133+
134+
// Session switcharooney again
135+
FuriThreadStdoutWriteCallback prev_stdout = furi_thread_get_stdout_callback();
136+
cli_session_close(global_cli);
100137
cli_session_open(global_cli, &cli_vcp);
138+
furi_thread_set_stdout_callback(prev_stdout);
101139
furi_record_close(RECORD_CLI);
102-
// Unblock waiting rx handler
103-
furi_stream_buffer_send(rx_stream, "_", 1, FuriWaitForever);
104-
// Reconfigure stdout_callback to cli_vcp
105-
if(cliThread != NULL) {
106-
((FuriThread_internal*)cliThread)->output.write_callback = cli_vcp.tx_stdout;
107-
}
108-
// At this point, all cli_vcp functions should be back.
109-
furi_stream_buffer_free(rx_stream);
110-
furi_stream_buffer_free(tx_stream);
111-
// Re-lock loader (to avoid crash on automatic unlock)
112-
Loader* loader = furi_record_open(RECORD_LOADER);
113-
Loader_internal* loader_i = (Loader_internal*)loader;
114-
loader_i->app.thread = prev_appthread;
115-
furi_record_close(RECORD_LOADER);
140+
141+
// Unblock waiting rx handler, restore old cli_vcp.tx_stdout
142+
furi_stream_buffer_send(cli_rx_stream, "_", 1, FuriWaitForever);
143+
144+
// At this point, all cli_vcp functions should be restored.
145+
146+
furi_stream_buffer_free(cli_rx_stream);
147+
furi_stream_buffer_free(cli_tx_stream);
148+
cli_rx_stream = NULL;
149+
cli_tx_stream = NULL;
116150
}

cli_control.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

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

cligui_main.c

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ static void cligui_tick_event_cb(void* context) {
4141
UNUSED(app);
4242
}
4343

44-
ViewPortInputCallback prev_input_callback;
4544
volatile bool persistent_exit = false;
46-
static void input_callback_wrapper(InputEvent* event, void* context) {
45+
static void input_callback(const void* event_ptr, void* context) {
46+
InputEvent* event = (InputEvent*)event_ptr;
4747
CliguiApp* app = context;
4848
if(event->type == InputTypeLong && event->key == InputKeyBack) {
4949
persistent_exit = false;
@@ -60,25 +60,21 @@ static void input_callback_wrapper(InputEvent* event, void* context) {
6060
} else {
6161
console_output_input_handler(app, event);
6262
}
63-
prev_input_callback(event, app->view_dispatcher);
6463
}
6564

6665
int32_t cligui_main(void* p) {
6766
UNUSED(p);
6867
CliguiApp* cligui = malloc(sizeof(CliguiApp));
6968
cligui->data = malloc(sizeof(CliguiData));
7069

71-
latch_tx_handler();
72-
cligui->data->streams.app_tx = rx_stream;
73-
cligui->data->streams.app_rx = tx_stream;
70+
clicontrol_hijack(512, 512);
71+
cligui->data->streams.app_tx = cli_rx_stream;
72+
cligui->data->streams.app_rx = cli_tx_stream;
7473

7574
cligui->gui = furi_record_open(RECORD_GUI);
7675
cligui->view_dispatcher = view_dispatcher_alloc();
77-
cligui->view_dispatcher_i = (ViewDispatcher_internal*)(cligui->view_dispatcher);
78-
prev_input_callback =
79-
((ViewPort_internal*)cligui->view_dispatcher_i->view_port)->input_callback;
80-
view_port_input_callback_set(
81-
cligui->view_dispatcher_i->view_port, input_callback_wrapper, cligui);
76+
FuriPubSub* input_events = furi_record_open(RECORD_INPUT_EVENTS);
77+
FuriPubSubSubscription* input_events_sub = furi_pubsub_subscribe(input_events, input_callback, (void*)cligui);
8278
view_dispatcher_enable_queue(cligui->view_dispatcher);
8379
view_dispatcher_set_event_callback_context(cligui->view_dispatcher, cligui);
8480
view_dispatcher_set_custom_event_callback(cligui->view_dispatcher, cligui_custom_event_cb);
@@ -122,9 +118,12 @@ int32_t cligui_main(void* p) {
122118
text_input_free(cligui->text_input);
123119
view_dispatcher_free(cligui->view_dispatcher);
124120

125-
unlatch_tx_handler(persistent_exit);
121+
clicontrol_unhijack(persistent_exit);
122+
123+
furi_pubsub_unsubscribe(input_events, input_events_sub);
126124

127125
furi_record_close(RECORD_GUI);
126+
furi_record_close(RECORD_INPUT_EVENTS);
128127

129128
free(cligui->data);
130129
free(cligui);

cligui_main_i.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#include <gui/modules/text_input.h>
1212
#include <m-dict.h>
1313
#include <loader/loader.h>
14-
#include "internal_defs.h"
1514

1615
#define TEXT_BOX_STORE_SIZE (4096)
1716
#define TEXT_INPUT_STORE_SIZE (512)
@@ -37,5 +36,4 @@ typedef struct {
3736
char text_input_store[TEXT_INPUT_STORE_SIZE + 1];
3837
TextInput* text_input;
3938
ViewDispatcher* view_dispatcher;
40-
ViewDispatcher_internal* view_dispatcher_i;
4139
} CliguiApp;

0 commit comments

Comments
 (0)