1
mirror of https://github.com/flipperdevices/flipperzero-firmware.git synced 2025-12-12 04:41:26 +04:00

[FL-3954, FL-3955] New CLI architecture (#4111)

* feat: FuriThread stdin

* ci: fix f18

* feat: stdio callback context

* feat: FuriPipe

* POTENTIALLY EXPLOSIVE pipe welding

* fix: non-explosive welding

* Revert welding

* docs: furi_pipe

* feat: pipe event loop integration

* update f18 sdk

* f18

* docs: make doxygen happy

* fix: event loop not triggering when pipe attached to stdio

* fix: partial stdout in pipe

* allow simultaneous in and out subscription in event loop

* feat: vcp i/o

* feat: cli ansi stuffs and history

* feat: more line editing

* working but slow cli rewrite

* restore previous speed after 4 days of debugging 🥲

* fix: cli_app_should_stop

* fix: cli and event_loop memory leaks

* style: remove commented out code

* ci: fix pvs warnings

* fix: unit tests, event_loop crash

* ci: fix build

* ci: silence pvs warning

* feat: cli gpio

* ci: fix formatting

* Fix memory leak during event loop unsubscription

* Event better memory leak fix

* feat: cli completions

* Merge remote-tracking branch 'origin/dev' into portasynthinca3/3928-cli-threads

* merge fixups

* temporarily exclude speaker_debug app

* pvs and unit tests fixups

* feat: commands in fals

* move commands out of flash, code cleanup

* ci: fix errors

* fix: run commands in buffer when stopping session

* speedup cli file transfer

* fix f18

* separate cli_shell into modules

* fix pvs warning

* fix qflipper refusing to connect

* remove temp debug logs

* remove erroneous conclusion

* Fix memory leak during event loop unsubscription

* Event better memory leak fix

* unit test for the fix

* improve thread stdio callback signatures

* pipe stdout timeout

* update api symbols

* fix f18, formatting

* fix pvs warnings

* increase stack size, hope to fix unit tests

* cli: revert flag changes

* cli: fix formatting

* cli, fbt: loopback perf benchmark

* thread, event_loop: subscribing to thread flags

* cli: signal internal events using thread flags, improve performance

* fix f18, formatting

* event_loop: fix crash

* storage_cli: increase write_chunk buffer size again

* cli: explanation for order=0

* thread, event_loop: thread flags callback refactor

* cli: increase stack size

* cli: rename cli_app_should_stop -> cli_is_pipe_broken_or_is_etx_next_char

* cli: use plain array instead of mlib for history

* cli: prepend file name to static fns

* cli: fix formatting

* cli_shell: increase stack size

* cli: fix rpc lockup

* cli: better lockup fix

* cli: fix f18

* fix merge

---------

Co-authored-by: Georgii Surkov <georgii.surkov@outlook.com>
Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
Anna Antonenko
2025-04-02 22:10:10 +04:00
committed by GitHub
parent 5786066512
commit 13333edd30
60 changed files with 2074 additions and 1339 deletions

View File

@@ -41,6 +41,16 @@ extern "C" {
#define CLAMP(x, upper, lower) (MIN(upper, MAX(x, lower)))
#endif
#ifndef CLAMP_WRAPAROUND
#define CLAMP_WRAPAROUND(x, upper, lower) \
({ \
__typeof__(x) _x = (x); \
__typeof__(upper) _upper = (upper); \
__typeof__(lower) _lower = (lower); \
(_x > _upper) ? _lower : ((_x < _lower) ? _upper : _x); \
})
#endif
#ifndef COUNT_OF
#define COUNT_OF(x) (sizeof(x) / sizeof(x[0]))
#endif

View File

@@ -78,6 +78,7 @@ void furi_event_loop_free(FuriEventLoop* instance) {
furi_event_loop_process_timer_queue(instance);
furi_check(TimerList_empty_p(instance->timer_list));
furi_check(WaitingList_empty_p(instance->waiting_list));
furi_check(!instance->are_thread_flags_subscribed);
FuriEventLoopTree_clear(instance->tree);
PendingQueue_clear(instance->pending_queue);
@@ -243,6 +244,10 @@ void furi_event_loop_run(FuriEventLoop* instance) {
} else if(flags & FuriEventLoopFlagPending) {
furi_event_loop_process_pending_callbacks(instance);
} else if(flags & FuriEventLoopFlagThreadFlag) {
if(instance->are_thread_flags_subscribed)
instance->thread_flags_callback(instance->thread_flags_callback_context);
} else {
furi_crash();
}
@@ -416,6 +421,24 @@ void furi_event_loop_subscribe_mutex(
instance, mutex, &furi_mutex_event_loop_contract, event, callback, context);
}
void furi_event_loop_subscribe_thread_flags(
FuriEventLoop* instance,
FuriEventLoopThreadFlagsCallback callback,
void* context) {
furi_check(instance);
furi_check(callback);
furi_check(!instance->are_thread_flags_subscribed);
instance->are_thread_flags_subscribed = true;
instance->thread_flags_callback = callback;
instance->thread_flags_callback_context = context;
}
void furi_event_loop_unsubscribe_thread_flags(FuriEventLoop* instance) {
furi_check(instance);
furi_check(instance->are_thread_flags_subscribed);
instance->are_thread_flags_subscribed = false;
}
/**
* Public generic unsubscription API
*/
@@ -538,6 +561,25 @@ static bool furi_event_loop_item_is_waiting(FuriEventLoopItem* instance) {
return instance->WaitingList.prev || instance->WaitingList.next;
}
void furi_event_loop_thread_flag_callback(FuriThreadId thread_id) {
TaskHandle_t hTask = (TaskHandle_t)thread_id;
BaseType_t yield;
if(FURI_IS_IRQ_MODE()) {
yield = pdFALSE;
(void)xTaskNotifyIndexedFromISR(
hTask,
FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX,
FuriEventLoopFlagThreadFlag,
eSetBits,
&yield);
portYIELD_FROM_ISR(yield);
} else {
(void)xTaskNotifyIndexed(
hTask, FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX, FuriEventLoopFlagThreadFlag, eSetBits);
}
}
/*
* Internal event loop link API, used by supported primitives
*/

View File

@@ -203,6 +203,12 @@ typedef void FuriEventLoopObject;
*/
typedef void (*FuriEventLoopEventCallback)(FuriEventLoopObject* object, void* context);
/** Callback type for event loop thread flag events
*
* @param context The context that was provided upon subscription
*/
typedef void (*FuriEventLoopThreadFlagsCallback)(void* context);
/** Opaque event flag type */
typedef struct FuriEventFlag FuriEventFlag;
@@ -304,6 +310,23 @@ void furi_event_loop_subscribe_mutex(
FuriEventLoopEventCallback callback,
void* context);
/** Subscribe to thread flag events of the current thread
*
* @param instance The Event Loop instance
* @param callback The callback to call when a flag has been set
* @param context The context for callback
*/
void furi_event_loop_subscribe_thread_flags(
FuriEventLoop* instance,
FuriEventLoopThreadFlagsCallback callback,
void* context);
/** Unsubscribe from thread flag events of the current thread
*
* @param instance The Event Loop instance
*/
void furi_event_loop_unsubscribe_thread_flags(FuriEventLoop* instance);
/** Unsubscribe from events (common)
*
* @param instance The Event Loop instance

View File

@@ -4,12 +4,14 @@
#include "event_loop_link_i.h"
#include "event_loop_timer_i.h"
#include "event_loop_tick_i.h"
#include "event_loop_thread_flag_interface.h"
#include <m-list.h>
#include <m-bptree.h>
#include <m-i-list.h>
#include "thread.h"
#include "thread_i.h"
struct FuriEventLoopItem {
// Source
@@ -50,11 +52,12 @@ typedef enum {
FuriEventLoopFlagStop = (1 << 1),
FuriEventLoopFlagTimer = (1 << 2),
FuriEventLoopFlagPending = (1 << 3),
FuriEventLoopFlagThreadFlag = (1 << 4),
} FuriEventLoopFlag;
#define FuriEventLoopFlagAll \
(FuriEventLoopFlagEvent | FuriEventLoopFlagStop | FuriEventLoopFlagTimer | \
FuriEventLoopFlagPending)
FuriEventLoopFlagPending | FuriEventLoopFlagThreadFlag)
typedef enum {
FuriEventLoopProcessStatusComplete,
@@ -94,4 +97,9 @@ struct FuriEventLoop {
PendingQueue_t pending_queue;
// Tick event
FuriEventLoopTick tick;
// Thread flags callback
bool are_thread_flags_subscribed;
FuriEventLoopThreadFlagsCallback thread_flags_callback;
void* thread_flags_callback_context;
};

View File

@@ -0,0 +1,10 @@
#pragma once
#include "thread.h"
/**
* @brief Notify `FuriEventLoop` that `furi_thread_flags_set` has been called
*
* @param thread_id Thread id
*/
extern void furi_event_loop_thread_flag_callback(FuriThreadId thread_id);

View File

@@ -7,6 +7,7 @@
#include "check.h"
#include "common_defines.h"
#include "string.h"
#include "event_loop_thread_flag_interface.h"
#include "log.h"
#include <furi_hal_rtc.h>
@@ -501,6 +502,9 @@ uint32_t furi_thread_flags_set(FuriThreadId thread_id, uint32_t flags) {
(void)xTaskNotifyAndQueryIndexed(hTask, THREAD_NOTIFY_INDEX, 0, eNoAction, &rflags);
}
}
furi_event_loop_thread_flag_callback(thread_id);
/* Return flags after setting */
return rflags;
}