vcp, cli: Handle Tx/Rx events before Connect/Disconnect + extra fixes (#4181)

* cli_vcp: handle tx/rx before connext/disconnect

* cli_vcp: disable trace

* cli_perf: advanced error reporting

* cli_vcp: reset tx flag directly in event handler

* fix formatting

* cli_vcp: make tx flag volatile

* storage_settings: fix scene ids

* cli_shell: add safety check to set_prompt

* cli_registry: move from bptree to dict, fix memory leak

* cli_vcp: go back to message queue for event signaling

* loader: move BeforeLoad event even earlier

* fix formatting
This commit is contained in:
Anna Antonenko
2025-04-11 14:53:10 +04:00
committed by GitHub
parent 5f66425671
commit 096c088bf1
9 changed files with 92 additions and 82 deletions

View File

@@ -30,27 +30,23 @@ typedef struct {
} CliVcpMessage;
typedef enum {
CliVcpInternalEventConnected = (1 << 0),
CliVcpInternalEventDisconnected = (1 << 1),
CliVcpInternalEventTxDone = (1 << 2),
CliVcpInternalEventRx = (1 << 3),
CliVcpInternalEventConnected,
CliVcpInternalEventDisconnected,
CliVcpInternalEventTxDone,
CliVcpInternalEventRx,
} CliVcpInternalEvent;
#define CliVcpInternalEventAll \
(CliVcpInternalEventConnected | CliVcpInternalEventDisconnected | CliVcpInternalEventTxDone | \
CliVcpInternalEventRx)
struct CliVcp {
FuriEventLoop* event_loop;
FuriMessageQueue* message_queue; // <! external messages
FuriThreadId thread_id;
FuriMessageQueue* internal_evt_queue;
bool is_enabled, is_connected;
FuriHalUsbInterface* previous_interface;
PipeSide* own_pipe;
PipeSide* shell_pipe;
bool is_currently_transmitting;
volatile bool is_currently_transmitting;
size_t previous_tx_length;
CliRegistry* main_registry;
@@ -101,11 +97,12 @@ static void cli_vcp_maybe_receive_data(CliVcp* cli_vcp) {
// =============
static void cli_vcp_signal_internal_event(CliVcp* cli_vcp, CliVcpInternalEvent event) {
furi_thread_flags_set(cli_vcp->thread_id, event);
furi_check(furi_message_queue_put(cli_vcp->internal_evt_queue, &event, 0) == FuriStatusOk);
}
static void cli_vcp_cdc_tx_done(void* context) {
CliVcp* cli_vcp = context;
cli_vcp->is_currently_transmitting = false;
cli_vcp_signal_internal_event(cli_vcp, CliVcpInternalEventTxDone);
}
@@ -190,12 +187,25 @@ static void cli_vcp_message_received(FuriEventLoopObject* object, void* context)
/**
* Processes messages arriving from CDC event callbacks
*/
static void cli_vcp_internal_event_happened(void* context) {
static void cli_vcp_internal_event_happened(FuriEventLoopObject* object, void* context) {
CliVcp* cli_vcp = context;
CliVcpInternalEvent event = furi_thread_flags_wait(CliVcpInternalEventAll, FuriFlagWaitAny, 0);
furi_check(!(event & FuriFlagError));
CliVcpInternalEvent event;
furi_check(furi_message_queue_get(object, &event, 0) == FuriStatusOk);
if(event & CliVcpInternalEventDisconnected) {
switch(event) {
case CliVcpInternalEventRx: {
VCP_TRACE(TAG, "Rx");
cli_vcp_maybe_receive_data(cli_vcp);
break;
}
case CliVcpInternalEventTxDone: {
VCP_TRACE(TAG, "TxDone");
cli_vcp_maybe_send_data(cli_vcp);
break;
}
case CliVcpInternalEventDisconnected: {
if(!cli_vcp->is_connected) return;
FURI_LOG_D(TAG, "Disconnected");
cli_vcp->is_connected = false;
@@ -204,9 +214,10 @@ static void cli_vcp_internal_event_happened(void* context) {
pipe_detach_from_event_loop(cli_vcp->own_pipe);
pipe_free(cli_vcp->own_pipe);
cli_vcp->own_pipe = NULL;
break;
}
if(event & CliVcpInternalEventConnected) {
case CliVcpInternalEventConnected: {
if(cli_vcp->is_connected) return;
FURI_LOG_D(TAG, "Connected");
cli_vcp->is_connected = true;
@@ -233,17 +244,8 @@ static void cli_vcp_internal_event_happened(void* context) {
cli_vcp->shell = cli_shell_alloc(
cli_main_motd, NULL, cli_vcp->shell_pipe, cli_vcp->main_registry, &cli_main_ext_config);
cli_shell_start(cli_vcp->shell);
break;
}
if(event & CliVcpInternalEventRx) {
VCP_TRACE(TAG, "Rx");
cli_vcp_maybe_receive_data(cli_vcp);
}
if(event & CliVcpInternalEventTxDone) {
VCP_TRACE(TAG, "TxDone");
cli_vcp->is_currently_transmitting = false;
cli_vcp_maybe_send_data(cli_vcp);
}
}
@@ -253,7 +255,6 @@ static void cli_vcp_internal_event_happened(void* context) {
static CliVcp* cli_vcp_alloc(void) {
CliVcp* cli_vcp = malloc(sizeof(CliVcp));
cli_vcp->thread_id = furi_thread_get_current_id();
cli_vcp->event_loop = furi_event_loop_alloc();
@@ -265,8 +266,14 @@ static CliVcp* cli_vcp_alloc(void) {
cli_vcp_message_received,
cli_vcp);
furi_event_loop_subscribe_thread_flags(
cli_vcp->event_loop, cli_vcp_internal_event_happened, cli_vcp);
cli_vcp->internal_evt_queue =
furi_message_queue_alloc(VCP_MESSAGE_Q_LEN, sizeof(CliVcpInternalEvent));
furi_event_loop_subscribe_message_queue(
cli_vcp->event_loop,
cli_vcp->internal_evt_queue,
FuriEventLoopEventIn,
cli_vcp_internal_event_happened,
cli_vcp);
cli_vcp->main_registry = furi_record_open(RECORD_CLI);

View File

@@ -418,9 +418,6 @@ static void loader_start_internal_app(
const FlipperInternalApplication* app,
const char* args) {
FURI_LOG_I(TAG, "Starting %s", app->name);
LoaderEvent event;
event.type = LoaderEventTypeApplicationBeforeLoad;
furi_pubsub_publish(loader->pubsub, &event);
// store args
furi_assert(loader->app.args == NULL);
@@ -508,10 +505,6 @@ static LoaderMessageLoaderStatusResult loader_start_external_app(
result.value = loader_make_success_status(error_message);
result.error = LoaderStatusErrorUnknown;
LoaderEvent event;
event.type = LoaderEventTypeApplicationBeforeLoad;
furi_pubsub_publish(loader->pubsub, &event);
do {
loader->app.fap = flipper_application_alloc(storage, firmware_api_interface);
size_t start = furi_get_tick();
@@ -566,6 +559,7 @@ static LoaderMessageLoaderStatusResult loader_start_external_app(
if(result.value != LoaderStatusOk) {
flipper_application_free(loader->app.fap);
loader->app.fap = NULL;
LoaderEvent event;
event.type = LoaderEventTypeApplicationLoadFailed;
furi_pubsub_publish(loader->pubsub, &event);
}
@@ -615,6 +609,10 @@ static LoaderMessageLoaderStatusResult loader_do_start_by_name(
status.value = loader_make_success_status(error_message);
status.error = LoaderStatusErrorUnknown;
LoaderEvent event;
event.type = LoaderEventTypeApplicationBeforeLoad;
furi_pubsub_publish(loader->pubsub, &event);
do {
// check lock
if(loader_do_is_locked(loader)) {