Skip to content

Commit

Permalink
feat: commands in fals
Browse files Browse the repository at this point in the history
  • Loading branch information
portasynthinca3 committed Dec 25, 2024
1 parent 0916aeb commit 82c1e71
Show file tree
Hide file tree
Showing 15 changed files with 379 additions and 52 deletions.
4 changes: 2 additions & 2 deletions applications/main/application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ App(
name="On start hooks",
apptype=FlipperAppType.METAPACKAGE,
provides=[
"cli_start",
"cli",
"ibutton_start",
# "onewire_start",
"onewire_start",
"subghz_start",
"infrared_start",
"lfrfid_start",
Expand Down
10 changes: 5 additions & 5 deletions applications/main/onewire/onewire_cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

#include <one_wire/one_wire_host.h>

static void onewire_cli(Cli* cli, FuriString* args, void* context);
static void onewire_cli(PipeSide* pipe, FuriString* args, void* context);

void onewire_on_system_start(void) {
#ifdef SRV_CLI
Expand All @@ -23,8 +23,8 @@ static void onewire_cli_print_usage(void) {
printf("onewire search\r\n");
}

static void onewire_cli_search(Cli* cli) {
UNUSED(cli);
static void onewire_cli_search(PipeSide* pipe) {
UNUSED(pipe);
OneWireHost* onewire = onewire_host_alloc(&gpio_ibutton);
uint8_t address[8];
bool done = false;
Expand Down Expand Up @@ -53,7 +53,7 @@ static void onewire_cli_search(Cli* cli) {
onewire_host_free(onewire);
}

void onewire_cli(Cli* cli, FuriString* args, void* context) {
void onewire_cli(PipeSide* pipe, FuriString* args, void* context) {
UNUSED(context);
FuriString* cmd;
cmd = furi_string_alloc();
Expand All @@ -65,7 +65,7 @@ void onewire_cli(Cli* cli, FuriString* args, void* context) {
}

if(furi_string_cmp_str(cmd, "search") == 0) {
onewire_cli_search(cli);
onewire_cli_search(pipe);
}

furi_string_free(cmd);
Expand Down
2 changes: 1 addition & 1 deletion applications/services/bt/application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ App(
entry_point="bt_srv",
cdefines=["SRV_BT"],
requires=[
"cli_start",
"cli",
"dialogs",
],
provides=[
Expand Down
18 changes: 17 additions & 1 deletion applications/services/cli/application.fam
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
App(
appid="cli_start",
appid="cli",
apptype=FlipperAppType.STARTUP,
entry_point="cli_on_system_start",
cdefines=["SRV_CLI"],
Expand All @@ -23,3 +23,19 @@ App(
sdk_headers=["cli_vcp.h"],
sources=["cli_vcp.c"],
)

App(
appid="cli_hello_world",
apptype=FlipperAppType.PLUGIN,
entry_point="cli_hello_world_ep",
requires=["cli"],
sources=["commands/hello_world.c"],
)

App(
appid="cli_neofetch",
apptype=FlipperAppType.PLUGIN,
entry_point="cli_neofetch_ep",
requires=["cli"],
sources=["commands/neofetch.c"],
)
51 changes: 50 additions & 1 deletion applications/services/cli/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include "cli_ansi.h"
#include <toolbox/pipe.h>

#define TAG "cli"

struct Cli {
CliCommandTree_t commands;
FuriMutex* mutex;
Expand Down Expand Up @@ -32,10 +34,10 @@ void cli_add_command(
furi_check(furi_string_search_char(name_str, ' ') == FURI_STRING_FAILURE);

CliCommand command = {
.name = name,
.context = context,
.execute_callback = callback,
.flags = flags,
.stack_depth = CLI_BUILTIN_COMMAND_STACK_SIZE,
};

furi_check(furi_mutex_acquire(cli->mutex, FuriWaitForever) == FuriStatusOk);
Expand Down Expand Up @@ -74,6 +76,53 @@ bool cli_get_command(Cli* cli, FuriString* command, CliCommand* result) {
return !!data;
}

void cli_enumerate_external_commands(Cli* cli) {
furi_check(cli);
furi_check(furi_mutex_acquire(cli->mutex, FuriWaitForever) == FuriStatusOk);
FURI_LOG_D(TAG, "Enumerating external commands");

// remove external commands
CliCommandTree_t internal_cmds;
CliCommandTree_init(internal_cmds);
for
M_EACH(item, cli->commands, CliCommandTree_t) {
if(!(item->value_ptr->flags & CliCommandFlagExternal))
CliCommandTree_set_at(internal_cmds, *item->key_ptr, *item->value_ptr);
}
CliCommandTree_move(cli->commands, internal_cmds);

// iterate over files in plugin directory
Storage* storage = furi_record_open(RECORD_STORAGE);
File* plogin_dir = storage_file_alloc(storage);

if(storage_dir_open(plogin_dir, CLI_COMMANDS_PATH)) {
char plugin_filename[64];
FuriString* plugin_name = furi_string_alloc();

while(storage_dir_read(plogin_dir, NULL, plugin_filename, sizeof(plugin_filename))) {
FURI_LOG_T(TAG, "Plugin: %s", plugin_filename);
furi_string_set_str(plugin_name, plugin_filename);
furi_string_replace_all_str(plugin_name, ".fal", "");
furi_string_replace_at(plugin_name, 0, 4, ""); // remove "cli_" in the beginning
CliCommand command = {
.context = NULL,
.execute_callback = NULL,
.flags = CliCommandFlagExternal,
};
CliCommandTree_set_at(cli->commands, plugin_name, command);
}

furi_string_free(plugin_name);
}

storage_dir_close(plogin_dir);
storage_file_free(plogin_dir);
furi_record_close(RECORD_STORAGE);

FURI_LOG_D(TAG, "Finished enumerating external commands");
furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk);
}

void cli_lock_commands(Cli* cli) {
furi_assert(cli);
furi_check(furi_mutex_acquire(cli->mutex, FuriWaitForever) == FuriStatusOk);
Expand Down
18 changes: 14 additions & 4 deletions applications/services/cli/cli.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@ typedef enum {
CliCommandFlagParallelUnsafe = (1 << 0), /**< Unsafe to run in parallel with other apps */
CliCommandFlagInsomniaSafe = (1 << 1), /**< Safe to run with insomnia mode on */
CliCommandFlagDontAttachStdio = (1 << 2), /**< Do no attach I/O pipe to thread stdio */

// internal flags (do not set them yourselves!)

CliCommandFlagExternal = (1 << 3), /**< The command comes from a .fal file */
} CliCommandFlag;

/** Cli type anonymous structure */
typedef struct Cli Cli;

/**
* @brief CLI execution callbackpointer. Implement this interface and use
* `add_cli_command` or `cli_add_command_ex`.
* @brief CLI execution callback pointer. Implement this interface and use
* `add_cli_command`.
*
* This callback will be called from a separate thread spawned just for your
* command. The pipe will be installed as the thread's stdio, so you can use
Expand All @@ -44,8 +48,7 @@ typedef struct Cli Cli;
typedef void (*CliExecuteCallback)(PipeSide* pipe, FuriString* args, void* context);

/**
* @brief Registers a command with the CLI. Provides less options than
* `cli_add_command_ex`
* @brief Registers a command with the CLI.
*
* @param [in] cli Pointer to CLI instance
* @param [in] name Command name
Expand All @@ -68,6 +71,13 @@ void cli_add_command(
*/
void cli_delete_command(Cli* cli, const char* name);

/**
* @brief Reloads the list of externally available commands
*
* @param [in] cli pointer to cli instance
*/
void cli_enumerate_external_commands(Cli* cli);

/**
* @brief Detects if Ctrl+C has been pressed or session has been terminated
*
Expand Down
16 changes: 15 additions & 1 deletion applications/services/cli/cli_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void cli_command_help(PipeSide* pipe, FuriString* args, void* context) {
UNUSED(pipe);
UNUSED(args);
UNUSED(context);
printf("Built-in shell commands:" ANSI_FG_GREEN);
printf("Available commands:" ANSI_FG_GREEN);

// count non-hidden commands
Cli* cli = furi_record_open(RECORD_CLI);
Expand Down Expand Up @@ -91,6 +91,8 @@ void cli_command_help(PipeSide* pipe, FuriString* args, void* context) {
}
}

printf(ANSI_RESET
"\r\nIf you just added a new command and can't see it above, run `reload_ext_cmds`");
printf(ANSI_RESET "\r\nFind out more: https://docs.flipper.net/development/cli");

cli_unlock_commands(cli);
Expand Down Expand Up @@ -512,10 +514,22 @@ void cli_command_i2c(PipeSide* pipe, FuriString* args, void* context) {
furi_hal_i2c_release(&furi_hal_i2c_handle_external);
}

void cli_command_reload_external(PipeSide* pipe, FuriString* args, void* context) {
UNUSED(pipe);
UNUSED(args);
UNUSED(context);
Cli* cli = furi_record_open(RECORD_CLI);
cli_enumerate_external_commands(cli);
furi_record_close(RECORD_CLI);
printf("OK!");
}

void cli_commands_init(Cli* cli) {
cli_add_command(cli, "!", CliCommandFlagDefault, cli_command_info, (void*)true);
cli_add_command(cli, "info", CliCommandFlagDefault, cli_command_info, NULL);
cli_add_command(cli, "device_info", CliCommandFlagDefault, cli_command_info, (void*)true);
cli_add_command(
cli, "reload_ext_cmds", CliCommandFlagDefault, cli_command_reload_external, NULL);

cli_add_command(cli, "?", CliCommandFlagDefault, cli_command_help, NULL);
cli_add_command(cli, "help", CliCommandFlagDefault, cli_command_help, NULL);
Expand Down
31 changes: 30 additions & 1 deletion applications/services/cli/cli_commands.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
#pragma once

#include "cli_i.h"
#include "cli.h"
#include <flipper_application/flipper_application.h>

void cli_commands_init(Cli* cli);

#define PLUGIN_APP_ID "cli"
#define PLUGIN_API_VERSION 1

typedef struct {
char* name;
CliExecuteCallback execute_callback;
CliCommandFlag flags;
size_t stack_depth;
} CliCommandDescriptor;

#define CLI_COMMAND_INTERFACE(name, execute_callback, flags, stack_depth) \
static const CliCommandDescriptor cli_##name##_desc = { \
#name, \
&execute_callback, \
flags, \
stack_depth, \
}; \
\
static const FlipperAppPluginDescriptor plugin_descriptor = { \
.appid = PLUGIN_APP_ID, \
.ep_api_version = PLUGIN_API_VERSION, \
.entry_point = &cli_##name##_desc, \
}; \
\
const FlipperAppPluginDescriptor* cli_##name##_ep(void) { \
return &plugin_descriptor; \
}
5 changes: 4 additions & 1 deletion applications/services/cli/cli_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@
extern "C" {
#endif

#define CLI_BUILTIN_COMMAND_STACK_SIZE (3 * 1024U)
#define CLI_COMMANDS_PATH "/ext/apps_data/cli/plugins"

typedef struct {
const char* name; //<! Command name
void* context; //<! Context passed to callbacks
CliExecuteCallback execute_callback; //<! Callback for command execution
CliCommandFlag flags;
size_t stack_depth;
} CliCommand;

#define CLI_COMMANDS_TREE_RANK 4
Expand Down
Loading

0 comments on commit 82c1e71

Please sign in to comment.