mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-06-16 20:09:44 -07:00
CLI: More commands as plugins on SD -6KB DFU, refactor plugin wrapper, (#276)
* Unused icons to check later * Exclude disabled icons from firmware * Format * CLI: Test moving more cmds to plugins * CLI: Macro template for plugin wrapper * Fix plugin filenames * Retrofit older cli wrappers * Fix unused * Fix manifests * Add explanation * Revert "Unused icons to check later" This reverts commitb7f98e344c. * Revert "Exclude disabled icons from firmware" This reverts commitab62e99898. * Add back toplevel chat command * Add DFU size to github comment * Fix build * Fix BT CLI preload fail * Add these back * Fix CLI command gpio preload fail * Fix input command * These can stay * Fix negative size rounding * Update changelog * Fix DFU size calc
This commit is contained in:
@@ -119,6 +119,20 @@ jobs:
|
||||
tar czpf "artifacts/flipper-z-any-scripts-${SUFFIX}.tgz" scripts
|
||||
cp build/core2_firmware.tgz "artifacts/flipper-z-any-core2_firmware-${SUFFIX}.tgz"
|
||||
|
||||
- name: "Calculate DFU sizes"
|
||||
env:
|
||||
INDEXER_URL: ${{ secrets.INDEXER_URL }}
|
||||
if: ${{ env.INDEXER_URL != '' && github.event.pull_request && matrix.target == env.DEFAULT_TARGET }}
|
||||
run: |
|
||||
curl -L "${{ secrets.INDEXER_URL }}"/firmware/development/f7/full_dfu -o dev.dfu
|
||||
dfu_size_new=$(du --apparent-size -B 1 artifacts/flipper-z-${TARGET}-full-*.dfu | cut -f1)
|
||||
dfu_size_dev=$(du --apparent-size -B 1 dev.dfu | cut -f1)
|
||||
dfu_size_diff=$((dfu_size_new - dfu_size_dev))
|
||||
DFU_SIZE=$(echo ${dfu_size_new}B | sed -r 's/^([0-9]+)([0-9]{2})([0-9])B/\1.\2K/')
|
||||
DFU_DIFF=$(echo ${dfu_size_diff}B | sed -r 's/^(-?[0-9]+)([0-9]{2})([0-9])B/\1.\2K/' | sed -r 's/^([^-])/+\1/')
|
||||
echo "DFU_SIZE=$DFU_SIZE" >> $GITHUB_ENV
|
||||
echo "DFU_DIFF=$DFU_DIFF" >> $GITHUB_ENV
|
||||
|
||||
- name: "Upload artifacts to update server"
|
||||
env:
|
||||
INDEXER_URL: ${{ secrets.INDEXER_URL }}
|
||||
@@ -155,6 +169,7 @@ jobs:
|
||||
**Compiled ${{ matrix.target }} firmware for commit `${{steps.names.outputs.commit_sha}}`:**
|
||||
- [☁️ Flipper Lab/App](https://lab.flipper.net/?url=${{secrets.INDEXER_URL}}/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-update-${{steps.names.outputs.suffix}}.tgz&channel=mntm-${{steps.names.outputs.branch_name}}&version=${{steps.names.outputs.commit_sha}})
|
||||
- [📦 qFlipper Package](${{secrets.INDEXER_URL}}/builds/firmware/${{steps.names.outputs.branch_name}}/flipper-z-${{steps.names.outputs.default_target}}-update-${{steps.names.outputs.suffix}}.tgz)
|
||||
- DFU Size: `${{ env.DFU_SIZE }}` (`${{ env.DFU_DIFF }}` from dev)
|
||||
edit-mode: replace
|
||||
|
||||
- name: Send devbuild webhook
|
||||
|
||||
+3
-1
@@ -133,7 +133,9 @@
|
||||
- UL: W5500 Ethernet: Various fixes and improvements (by @xMasterX)
|
||||
- OFW: SPI Mem Manager: Fixed UI rendering bug related to line breaks (by @portasynthinca3)
|
||||
- OFW: USB/BT Remote: Mouse clicker option to click as fast as possible (by @sumukhj1219)
|
||||
- CLI: Print plugin name on load fail (by @Willy-JL)
|
||||
- CLI:
|
||||
- Print plugin name on load fail (by @Willy-JL)
|
||||
- Move more commands as plugins on SD, refactor plugin wrapper (#276 by @Willy-JL)
|
||||
- NFC:
|
||||
- NDEF Parser:
|
||||
- Mifare Classic support (#265 by @luu176), protocol-agnostic rewrite and more improvements (#265 by @Willy-JL)
|
||||
|
||||
@@ -25,6 +25,6 @@ App(
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
targets=["f7"],
|
||||
entry_point="ibutton_on_system_start",
|
||||
sources=["ibutton_start.c"],
|
||||
sources=["ibutton_cli.c"],
|
||||
order=60,
|
||||
)
|
||||
|
||||
@@ -8,6 +8,22 @@
|
||||
#include <ibutton/ibutton_worker.h>
|
||||
#include <ibutton/ibutton_protocols.h>
|
||||
|
||||
static void ibutton_cli(Cli* cli, FuriString* args, void* context);
|
||||
|
||||
#include <cli/cli_i.h>
|
||||
CLI_PLUGIN_WRAPPER("ibutton", ibutton_cli)
|
||||
|
||||
// app cli function
|
||||
void ibutton_on_system_start(void) {
|
||||
#ifdef SRV_CLI
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "ikey", CliCommandFlagDefault, ibutton_cli_wrapper, cli);
|
||||
furi_record_close(RECORD_CLI);
|
||||
#else
|
||||
UNUSED(ibutton_cli);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ibutton_cli_print_usage(void) {
|
||||
printf("Usage:\r\n");
|
||||
printf("ikey read\r\n");
|
||||
@@ -239,16 +255,3 @@ void ibutton_cli(Cli* cli, FuriString* args, void* context) {
|
||||
|
||||
furi_string_free(cmd);
|
||||
}
|
||||
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include <cli/cli_i.h>
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
.appid = CLI_PLUGIN_APP_ID,
|
||||
.ep_api_version = CLI_PLUGIN_API_VERSION,
|
||||
.entry_point = &ibutton_cli,
|
||||
};
|
||||
|
||||
const FlipperAppPluginDescriptor* ibutton_cli_plugin_ep(void) {
|
||||
return &plugin_descriptor;
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#include <cli/cli_i.h>
|
||||
|
||||
static void ibutton_cli_wrapper(Cli* cli, FuriString* args, void* context) {
|
||||
cli_plugin_wrapper("ibutton", cli, args, context);
|
||||
}
|
||||
|
||||
void ibutton_on_system_start(void) {
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "ikey", CliCommandFlagDefault, ibutton_cli_wrapper, cli);
|
||||
furi_record_close(RECORD_CLI);
|
||||
}
|
||||
@@ -17,7 +17,7 @@ App(
|
||||
appid="infrared_cli",
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="infrared_cli_plugin_ep",
|
||||
entry_point="infrared_cli_start_ir_plugin_ep",
|
||||
requires=["cli"],
|
||||
sources=[
|
||||
"infrared_cli.c",
|
||||
@@ -31,6 +31,6 @@ App(
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
targets=["f7"],
|
||||
entry_point="infrared_on_system_start",
|
||||
sources=["infrared_start.c"],
|
||||
sources=["infrared_cli.c"],
|
||||
order=20,
|
||||
)
|
||||
|
||||
@@ -555,15 +555,15 @@ static void infrared_cli_start_ir(Cli* cli, FuriString* args, void* context) {
|
||||
furi_string_free(command);
|
||||
}
|
||||
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include <cli/cli_i.h>
|
||||
CLI_PLUGIN_WRAPPER("infrared", infrared_cli_start_ir)
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
.appid = CLI_PLUGIN_APP_ID,
|
||||
.ep_api_version = CLI_PLUGIN_API_VERSION,
|
||||
.entry_point = &infrared_cli_start_ir,
|
||||
};
|
||||
|
||||
const FlipperAppPluginDescriptor* infrared_cli_plugin_ep(void) {
|
||||
return &plugin_descriptor;
|
||||
void infrared_on_system_start(void) {
|
||||
#ifdef SRV_CLI
|
||||
Cli* cli = (Cli*)furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "ir", CliCommandFlagDefault, infrared_cli_start_ir_wrapper, NULL);
|
||||
furi_record_close(RECORD_CLI);
|
||||
#else
|
||||
UNUSED(infrared_cli_start_ir);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#include <cli/cli_i.h>
|
||||
|
||||
static void infrared_cli_start_ir_wrapper(Cli* cli, FuriString* args, void* context) {
|
||||
cli_plugin_wrapper("infrared", cli, args, context);
|
||||
}
|
||||
|
||||
void infrared_on_system_start(void) {
|
||||
Cli* cli = (Cli*)furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "ir", CliCommandFlagDefault, infrared_cli_start_ir_wrapper, NULL);
|
||||
furi_record_close(RECORD_CLI);
|
||||
}
|
||||
@@ -25,6 +25,6 @@ App(
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
entry_point="lfrfid_on_system_start",
|
||||
sources=["lfrfid_start.c"],
|
||||
sources=["lfrfid_cli.c"],
|
||||
order=50,
|
||||
)
|
||||
|
||||
@@ -14,6 +14,18 @@
|
||||
#include <lfrfid/lfrfid_raw_file.h>
|
||||
#include <toolbox/pulse_protocols/pulse_glue.h>
|
||||
|
||||
static void lfrfid_cli(Cli* cli, FuriString* args, void* context);
|
||||
|
||||
#include <cli/cli_i.h>
|
||||
CLI_PLUGIN_WRAPPER("lfrfid", lfrfid_cli)
|
||||
|
||||
// app cli function
|
||||
void lfrfid_on_system_start(void) {
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "rfid", CliCommandFlagDefault, lfrfid_cli_wrapper, NULL);
|
||||
furi_record_close(RECORD_CLI);
|
||||
}
|
||||
|
||||
static void lfrfid_cli_print_usage(void) {
|
||||
printf("Usage:\r\n");
|
||||
printf("rfid read <optional: normal | indala> - read in ASK/PSK mode\r\n");
|
||||
@@ -568,16 +580,3 @@ static void lfrfid_cli(Cli* cli, FuriString* args, void* context) {
|
||||
|
||||
furi_string_free(cmd);
|
||||
}
|
||||
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include <cli/cli_i.h>
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
.appid = CLI_PLUGIN_APP_ID,
|
||||
.ep_api_version = CLI_PLUGIN_API_VERSION,
|
||||
.entry_point = &lfrfid_cli,
|
||||
};
|
||||
|
||||
const FlipperAppPluginDescriptor* lfrfid_cli_plugin_ep(void) {
|
||||
return &plugin_descriptor;
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#include <cli/cli_i.h>
|
||||
|
||||
static void lfrfid_cli_wrapper(Cli* cli, FuriString* args, void* context) {
|
||||
cli_plugin_wrapper("lfrfid", cli, args, context);
|
||||
}
|
||||
|
||||
void lfrfid_on_system_start(void) {
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "rfid", CliCommandFlagDefault, lfrfid_cli_wrapper, NULL);
|
||||
furi_record_close(RECORD_CLI);
|
||||
}
|
||||
@@ -352,6 +352,6 @@ App(
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
entry_point="nfc_on_system_start",
|
||||
sources=["nfc_start.c"],
|
||||
sources=["nfc_cli.c"],
|
||||
order=30,
|
||||
)
|
||||
|
||||
@@ -63,15 +63,15 @@ static void nfc_cli(Cli* cli, FuriString* args, void* context) {
|
||||
furi_string_free(cmd);
|
||||
}
|
||||
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include <cli/cli_i.h>
|
||||
CLI_PLUGIN_WRAPPER("nfc", nfc_cli)
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
.appid = CLI_PLUGIN_APP_ID,
|
||||
.ep_api_version = CLI_PLUGIN_API_VERSION,
|
||||
.entry_point = &nfc_cli,
|
||||
};
|
||||
|
||||
const FlipperAppPluginDescriptor* nfc_cli_plugin_ep(void) {
|
||||
return &plugin_descriptor;
|
||||
void nfc_on_system_start(void) {
|
||||
#ifdef SRV_CLI
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "nfc", CliCommandFlagDefault, nfc_cli_wrapper, NULL);
|
||||
furi_record_close(RECORD_CLI);
|
||||
#else
|
||||
UNUSED(nfc_cli);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#include <cli/cli_i.h>
|
||||
|
||||
static void nfc_cli_wrapper(Cli* cli, FuriString* args, void* context) {
|
||||
cli_plugin_wrapper("nfc", cli, args, context);
|
||||
}
|
||||
|
||||
void nfc_on_system_start(void) {
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "nfc", CliCommandFlagDefault, nfc_cli_wrapper, NULL);
|
||||
furi_record_close(RECORD_CLI);
|
||||
}
|
||||
@@ -11,6 +11,6 @@ App(
|
||||
appid="onewire_start",
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
entry_point="onewire_on_system_start",
|
||||
sources=["onewire_start.c"],
|
||||
sources=["onewire_cli.c"],
|
||||
order=60,
|
||||
)
|
||||
|
||||
@@ -6,6 +6,21 @@
|
||||
|
||||
#include <one_wire/one_wire_host.h>
|
||||
|
||||
static void onewire_cli(Cli* cli, FuriString* args, void* context);
|
||||
|
||||
#include <cli/cli_i.h>
|
||||
CLI_PLUGIN_WRAPPER("onewire", onewire_cli)
|
||||
|
||||
void onewire_on_system_start(void) {
|
||||
#ifdef SRV_CLI
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "onewire", CliCommandFlagDefault, onewire_cli_wrapper, cli);
|
||||
furi_record_close(RECORD_CLI);
|
||||
#else
|
||||
UNUSED(onewire_cli);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void onewire_cli_print_usage(void) {
|
||||
printf("Usage:\r\n");
|
||||
printf("onewire search\r\n");
|
||||
@@ -58,16 +73,3 @@ void onewire_cli(Cli* cli, FuriString* args, void* context) {
|
||||
|
||||
furi_string_free(cmd);
|
||||
}
|
||||
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include <cli/cli_i.h>
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
.appid = CLI_PLUGIN_APP_ID,
|
||||
.ep_api_version = CLI_PLUGIN_API_VERSION,
|
||||
.entry_point = &onewire_cli,
|
||||
};
|
||||
|
||||
const FlipperAppPluginDescriptor* onewire_cli_plugin_ep(void) {
|
||||
return &plugin_descriptor;
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#include <cli/cli_i.h>
|
||||
|
||||
static void onewire_cli_wrapper(Cli* cli, FuriString* args, void* context) {
|
||||
cli_plugin_wrapper("onewire", cli, args, context);
|
||||
}
|
||||
|
||||
void onewire_on_system_start(void) {
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "onewire", CliCommandFlagDefault, onewire_cli_wrapper, cli);
|
||||
furi_record_close(RECORD_CLI);
|
||||
}
|
||||
@@ -48,7 +48,7 @@ App(
|
||||
appid="subghz_cli",
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="subghz_cli_plugin_ep",
|
||||
entry_point="subghz_cli_command_plugin_ep",
|
||||
requires=["cli"],
|
||||
sources=["subghz_cli.c", "helpers/subghz_chat.c"],
|
||||
)
|
||||
@@ -59,7 +59,7 @@ App(
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
entry_point="subghz_on_system_start",
|
||||
# sources=["subghz_start.c"],
|
||||
# sources=["subghz_cli.c"],
|
||||
order=40,
|
||||
)
|
||||
|
||||
|
||||
@@ -1185,15 +1185,24 @@ static void subghz_cli_command(Cli* cli, FuriString* args, void* context) {
|
||||
furi_string_free(cmd);
|
||||
}
|
||||
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include <cli/cli_i.h>
|
||||
CLI_PLUGIN_WRAPPER("subghz", subghz_cli_command)
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
.appid = CLI_PLUGIN_APP_ID,
|
||||
.ep_api_version = CLI_PLUGIN_API_VERSION,
|
||||
.entry_point = &subghz_cli_command,
|
||||
};
|
||||
|
||||
const FlipperAppPluginDescriptor* subghz_cli_plugin_ep(void) {
|
||||
return &plugin_descriptor;
|
||||
static void subghz_cli_command_chat_wrapper(Cli* cli, FuriString* args, void* context) {
|
||||
furi_string_replace_at(args, 0, 0, "chat ");
|
||||
subghz_cli_command_wrapper(cli, args, context);
|
||||
}
|
||||
|
||||
void subghz_on_system_start(void) {
|
||||
#ifdef SRV_CLI
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
|
||||
cli_add_command(cli, "subghz", CliCommandFlagDefault, subghz_cli_command_wrapper, NULL);
|
||||
cli_add_command(cli, "chat", CliCommandFlagDefault, subghz_cli_command_chat_wrapper, NULL);
|
||||
|
||||
furi_record_close(RECORD_CLI);
|
||||
#else
|
||||
UNUSED(subghz_cli_command);
|
||||
UNUSED(subghz_cli_command_chat_wrapper);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
#include <cli/cli_i.h>
|
||||
|
||||
#include <storage/storage.h>
|
||||
#include <flipper.pb.h>
|
||||
#include <pb_decode.h>
|
||||
|
||||
#define SUBGHZ_REGION_FILENAME "/int/.region_data"
|
||||
|
||||
static void subghz_cli_command_wrapper(Cli* cli, FuriString* args, void* context) {
|
||||
cli_plugin_wrapper("subghz", cli, args, context);
|
||||
}
|
||||
|
||||
static void subghz_cli_command_chat_wrapper(Cli* cli, FuriString* args, void* context) {
|
||||
furi_string_replace_at(args, 0, 0, "chat ");
|
||||
subghz_cli_command_wrapper(cli, args, context);
|
||||
}
|
||||
|
||||
static bool
|
||||
subghz_on_system_start_istream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) {
|
||||
File* file = istream->state;
|
||||
size_t ret = storage_file_read(file, buf, count);
|
||||
return (count == ret);
|
||||
}
|
||||
|
||||
static bool subghz_on_system_start_istream_decode_band(
|
||||
pb_istream_t* stream,
|
||||
const pb_field_t* field,
|
||||
void** arg) {
|
||||
(void)field;
|
||||
FuriHalRegion* region = *arg;
|
||||
|
||||
PB_Region_Band band = {0};
|
||||
if(!pb_decode(stream, PB_Region_Band_fields, &band)) {
|
||||
FURI_LOG_E("SubGhzOnStart", "PB Region band decode error: %s", PB_GET_ERROR(stream));
|
||||
return false;
|
||||
}
|
||||
|
||||
region->bands_count += 1;
|
||||
region = realloc( //-V701
|
||||
region,
|
||||
sizeof(FuriHalRegion) + sizeof(FuriHalRegionBand) * region->bands_count);
|
||||
size_t pos = region->bands_count - 1;
|
||||
region->bands[pos].start = band.start;
|
||||
region->bands[pos].end = band.end;
|
||||
region->bands[pos].power_limit = band.power_limit;
|
||||
region->bands[pos].duty_cycle = band.duty_cycle;
|
||||
*arg = region;
|
||||
|
||||
FURI_LOG_I(
|
||||
"SubGhzOnStart",
|
||||
"Add allowed band: start %luHz, stop %luHz, power_limit %ddBm, duty_cycle %u%%",
|
||||
band.start,
|
||||
band.end,
|
||||
band.power_limit,
|
||||
band.duty_cycle);
|
||||
return true;
|
||||
}
|
||||
|
||||
void subghz_on_system_start(void) {
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "subghz", CliCommandFlagDefault, subghz_cli_command_wrapper, NULL);
|
||||
cli_add_command(cli, "chat", CliCommandFlagDefault, subghz_cli_command_chat_wrapper, NULL);
|
||||
furi_record_close(RECORD_CLI);
|
||||
|
||||
#ifdef SRV_STORAGE
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
File* file = storage_file_alloc(storage);
|
||||
FileInfo fileinfo = {0};
|
||||
PB_Region pb_region = {0};
|
||||
pb_region.bands.funcs.decode = subghz_on_system_start_istream_decode_band;
|
||||
|
||||
do {
|
||||
if(storage_common_stat(storage, SUBGHZ_REGION_FILENAME, &fileinfo) != FSE_OK ||
|
||||
fileinfo.size == 0) {
|
||||
FURI_LOG_W("SubGhzOnStart", "Region data is missing or empty");
|
||||
break;
|
||||
}
|
||||
|
||||
if(!storage_file_open(file, SUBGHZ_REGION_FILENAME, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
FURI_LOG_E("SubGhzOnStart", "Unable to open region data");
|
||||
break;
|
||||
}
|
||||
|
||||
pb_istream_t istream = {
|
||||
.callback = subghz_on_system_start_istream_read,
|
||||
.state = file,
|
||||
.errmsg = NULL,
|
||||
.bytes_left = fileinfo.size,
|
||||
};
|
||||
|
||||
pb_region.bands.arg = malloc(sizeof(FuriHalRegion));
|
||||
if(!pb_decode(&istream, PB_Region_fields, &pb_region)) {
|
||||
FURI_LOG_E("SubGhzOnStart", "Invalid region data");
|
||||
free(pb_region.bands.arg);
|
||||
break;
|
||||
}
|
||||
|
||||
FuriHalRegion* region = pb_region.bands.arg;
|
||||
memcpy(
|
||||
region->country_code,
|
||||
pb_region.country_code->bytes,
|
||||
pb_region.country_code->size < 4 ? pb_region.country_code->size : 3);
|
||||
furi_hal_region_set(region);
|
||||
} while(0);
|
||||
|
||||
pb_release(PB_Region_fields, &pb_region);
|
||||
storage_file_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
#else
|
||||
UNUSED(subghz_on_system_start_istream_decode_band);
|
||||
UNUSED(subghz_on_system_start_istream_read);
|
||||
#endif
|
||||
}
|
||||
@@ -227,15 +227,15 @@ static void bt_cli(Cli* cli, FuriString* args, void* context) {
|
||||
furi_record_close(RECORD_BT);
|
||||
}
|
||||
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include <cli/cli_i.h>
|
||||
CLI_PLUGIN_WRAPPER("bt", bt_cli)
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
.appid = CLI_PLUGIN_APP_ID,
|
||||
.ep_api_version = CLI_PLUGIN_API_VERSION,
|
||||
.entry_point = &bt_cli,
|
||||
};
|
||||
|
||||
const FlipperAppPluginDescriptor* bt_cli_plugin_ep(void) {
|
||||
return &plugin_descriptor;
|
||||
void bt_on_system_start(void) {
|
||||
#ifdef SRV_CLI
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, RECORD_BT, CliCommandFlagDefault, bt_cli_wrapper, NULL);
|
||||
furi_record_close(RECORD_CLI);
|
||||
#else
|
||||
UNUSED(bt_cli);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#include <cli/cli_i.h>
|
||||
#include "bt_service/bt.h"
|
||||
|
||||
static void bt_cli_wrapper(Cli* cli, FuriString* args, void* context) {
|
||||
cli_plugin_wrapper("bt", cli, args, context);
|
||||
}
|
||||
|
||||
void bt_on_system_start(void) {
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, RECORD_BT, CliCommandFlagDefault, bt_cli_wrapper, NULL);
|
||||
furi_record_close(RECORD_CLI);
|
||||
}
|
||||
@@ -8,3 +8,102 @@ App(
|
||||
order=30,
|
||||
sdk_headers=["cli.h", "cli_vcp.h"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="info_cli",
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="cli_command_info_plugin_ep",
|
||||
requires=["cli"],
|
||||
sources=["cli_commands.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="src_cli",
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="cli_command_src_plugin_ep",
|
||||
requires=["cli"],
|
||||
sources=["cli_commands.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="neofetch_cli",
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="cli_command_neofetch_plugin_ep",
|
||||
requires=["cli"],
|
||||
sources=["cli_commands.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="help_cli",
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="cli_command_help_plugin_ep",
|
||||
requires=["cli"],
|
||||
sources=["cli_commands.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="uptime_cli",
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="cli_command_uptime_plugin_ep",
|
||||
requires=["cli"],
|
||||
sources=["cli_commands.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="date_cli",
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="cli_command_date_plugin_ep",
|
||||
requires=["cli"],
|
||||
sources=["cli_commands.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="sysctl_cli",
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="cli_command_sysctl_plugin_ep",
|
||||
requires=["cli"],
|
||||
sources=["cli_commands.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="vibro_cli",
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="cli_command_vibro_plugin_ep",
|
||||
requires=["cli"],
|
||||
sources=["cli_commands.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="led_cli",
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="cli_command_led_plugin_ep",
|
||||
requires=["cli"],
|
||||
sources=["cli_commands.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="gpio_cli",
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="cli_command_gpio_plugin_ep",
|
||||
requires=["cli"],
|
||||
sources=["cli_commands.c", "cli_command_gpio.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="i2c_cli",
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="cli_command_i2c_plugin_ep",
|
||||
requires=["cli"],
|
||||
sources=["cli_commands.c"],
|
||||
)
|
||||
|
||||
@@ -682,33 +682,46 @@ void cli_command_i2c(Cli* cli, FuriString* args, void* context) {
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_external);
|
||||
}
|
||||
|
||||
CLI_PLUGIN_WRAPPER("info", cli_command_info)
|
||||
CLI_PLUGIN_WRAPPER("src", cli_command_src)
|
||||
CLI_PLUGIN_WRAPPER("neofetch", cli_command_neofetch)
|
||||
CLI_PLUGIN_WRAPPER("help", cli_command_help)
|
||||
CLI_PLUGIN_WRAPPER("uptime", cli_command_uptime)
|
||||
CLI_PLUGIN_WRAPPER("date", cli_command_date)
|
||||
CLI_PLUGIN_WRAPPER("sysctl", cli_command_sysctl)
|
||||
CLI_PLUGIN_WRAPPER("vibro", cli_command_vibro)
|
||||
CLI_PLUGIN_WRAPPER("led", cli_command_led)
|
||||
CLI_PLUGIN_WRAPPER("gpio", cli_command_gpio)
|
||||
CLI_PLUGIN_WRAPPER("i2c", cli_command_i2c)
|
||||
|
||||
void cli_commands_init(Cli* cli) {
|
||||
cli_add_command(cli, "!", CliCommandFlagParallelSafe, cli_command_info, (void*)true);
|
||||
cli_add_command(cli, "info", CliCommandFlagParallelSafe, cli_command_info, NULL);
|
||||
cli_add_command(cli, "device_info", CliCommandFlagParallelSafe, cli_command_info, (void*)true);
|
||||
cli_add_command(cli, "source", CliCommandFlagParallelSafe, cli_command_src, NULL);
|
||||
cli_add_command(cli, "src", CliCommandFlagParallelSafe, cli_command_src, NULL);
|
||||
cli_add_command(cli, "!", CliCommandFlagParallelSafe, cli_command_info_wrapper, (void*)true);
|
||||
cli_add_command(cli, "info", CliCommandFlagParallelSafe, cli_command_info_wrapper, NULL);
|
||||
cli_add_command(
|
||||
cli, "device_info", CliCommandFlagParallelSafe, cli_command_info_wrapper, (void*)true);
|
||||
cli_add_command(cli, "source", CliCommandFlagParallelSafe, cli_command_src_wrapper, NULL);
|
||||
cli_add_command(cli, "src", CliCommandFlagParallelSafe, cli_command_src_wrapper, NULL);
|
||||
cli_add_command(
|
||||
cli,
|
||||
"neofetch",
|
||||
CliCommandFlagParallelSafe | CliCommandFlagHidden,
|
||||
cli_command_neofetch,
|
||||
cli_command_neofetch_wrapper,
|
||||
NULL);
|
||||
|
||||
cli_add_command(cli, "?", CliCommandFlagParallelSafe, cli_command_help, NULL);
|
||||
cli_add_command(cli, "help", CliCommandFlagParallelSafe, cli_command_help, NULL);
|
||||
cli_add_command(cli, "?", CliCommandFlagParallelSafe, cli_command_help_wrapper, NULL);
|
||||
cli_add_command(cli, "help", CliCommandFlagParallelSafe, cli_command_help_wrapper, NULL);
|
||||
|
||||
cli_add_command(cli, "uptime", CliCommandFlagDefault, cli_command_uptime, NULL);
|
||||
cli_add_command(cli, "date", CliCommandFlagParallelSafe, cli_command_date, NULL);
|
||||
cli_add_command(cli, "uptime", CliCommandFlagDefault, cli_command_uptime_wrapper, NULL);
|
||||
cli_add_command(cli, "date", CliCommandFlagParallelSafe, cli_command_date_wrapper, NULL);
|
||||
cli_add_command(cli, "log", CliCommandFlagParallelSafe, cli_command_log, NULL);
|
||||
cli_add_command(cli, "l", CliCommandFlagParallelSafe, cli_command_log, NULL);
|
||||
cli_add_command(cli, "sysctl", CliCommandFlagDefault, cli_command_sysctl, NULL);
|
||||
cli_add_command(cli, "sysctl", CliCommandFlagDefault, cli_command_sysctl_wrapper, NULL);
|
||||
cli_add_command(cli, "top", CliCommandFlagParallelSafe, cli_command_top, NULL);
|
||||
cli_add_command(cli, "free", CliCommandFlagParallelSafe, cli_command_free, NULL);
|
||||
cli_add_command(cli, "free_blocks", CliCommandFlagParallelSafe, cli_command_free_blocks, NULL);
|
||||
|
||||
cli_add_command(cli, "vibro", CliCommandFlagDefault, cli_command_vibro, NULL);
|
||||
cli_add_command(cli, "led", CliCommandFlagDefault, cli_command_led, NULL);
|
||||
cli_add_command(cli, "gpio", CliCommandFlagDefault, cli_command_gpio, NULL);
|
||||
cli_add_command(cli, "i2c", CliCommandFlagDefault, cli_command_i2c, NULL);
|
||||
cli_add_command(cli, "vibro", CliCommandFlagDefault, cli_command_vibro_wrapper, NULL);
|
||||
cli_add_command(cli, "led", CliCommandFlagDefault, cli_command_led_wrapper, NULL);
|
||||
cli_add_command(cli, "gpio", CliCommandFlagDefault, cli_command_gpio_wrapper, NULL);
|
||||
cli_add_command(cli, "i2c", CliCommandFlagDefault, cli_command_i2c_wrapper, NULL);
|
||||
}
|
||||
|
||||
@@ -62,12 +62,28 @@ void cli_putc(Cli* cli, char c);
|
||||
|
||||
void cli_stdout_callback(void* _cookie, const char* data, size_t size);
|
||||
|
||||
// Wraps CLI commands to load from plugin file
|
||||
// Must call from CLI context, like dummy CLI command callback
|
||||
// You need to setup the plugin to compile correctly separately
|
||||
// CLI command wrapping to load from plugin file on SD card
|
||||
// Just need to:
|
||||
// - Use CLI_PLUGIN_WRAPPER("name", cmd_callback)
|
||||
// - Replace callback usages with cmd_callback_wrapper
|
||||
// - Add "name_cli" entry in app manifest to build as plugin
|
||||
void cli_plugin_wrapper(const char* name, Cli* cli, FuriString* args, void* context);
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#define CLI_PLUGIN_APP_ID "cli"
|
||||
#define CLI_PLUGIN_API_VERSION 1
|
||||
void cli_plugin_wrapper(const char* name, Cli* cli, FuriString* args, void* context);
|
||||
#define CLI_PLUGIN_WRAPPER(plugin_name_without_cli_suffix, cli_command_callback) \
|
||||
void cli_command_callback##_wrapper(Cli* cli, FuriString* args, void* context) { \
|
||||
cli_plugin_wrapper(plugin_name_without_cli_suffix, cli, args, context); \
|
||||
} \
|
||||
static const FlipperAppPluginDescriptor cli_command_callback##_plugin_descriptor = { \
|
||||
.appid = CLI_PLUGIN_APP_ID, \
|
||||
.ep_api_version = CLI_PLUGIN_API_VERSION, \
|
||||
.entry_point = &cli_command_callback, \
|
||||
}; \
|
||||
const FlipperAppPluginDescriptor* cli_command_callback##_plugin_ep(void) { \
|
||||
UNUSED(cli_command_callback##_wrapper); \
|
||||
return &cli_command_callback##_plugin_descriptor; \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -11,6 +11,6 @@ App(
|
||||
appid="crypto_start",
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
entry_point="crypto_on_system_start",
|
||||
sources=["crypto_start.c"],
|
||||
sources=["crypto_cli.c"],
|
||||
order=10,
|
||||
)
|
||||
|
||||
@@ -317,15 +317,15 @@ static void crypto_cli(Cli* cli, FuriString* args, void* context) {
|
||||
furi_string_free(cmd);
|
||||
}
|
||||
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include <cli/cli_i.h>
|
||||
CLI_PLUGIN_WRAPPER("crypto", crypto_cli)
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
.appid = CLI_PLUGIN_APP_ID,
|
||||
.ep_api_version = CLI_PLUGIN_API_VERSION,
|
||||
.entry_point = &crypto_cli,
|
||||
};
|
||||
|
||||
const FlipperAppPluginDescriptor* crypto_cli_plugin_ep(void) {
|
||||
return &plugin_descriptor;
|
||||
void crypto_on_system_start(void) {
|
||||
#ifdef SRV_CLI
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "crypto", CliCommandFlagDefault, crypto_cli_wrapper, NULL);
|
||||
furi_record_close(RECORD_CLI);
|
||||
#else
|
||||
UNUSED(crypto_cli);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#include <cli/cli_i.h>
|
||||
|
||||
static void crypto_cli_wrapper(Cli* cli, FuriString* args, void* context) {
|
||||
cli_plugin_wrapper("crypto", cli, args, context);
|
||||
}
|
||||
|
||||
void crypto_on_system_start(void) {
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "crypto", CliCommandFlagDefault, crypto_cli_wrapper, NULL);
|
||||
furi_record_close(RECORD_CLI);
|
||||
}
|
||||
@@ -25,7 +25,7 @@ typedef struct {
|
||||
} InputPinState;
|
||||
|
||||
/** Input CLI command handler */
|
||||
void input_cli(Cli* cli, FuriString* args, void* context);
|
||||
void input_cli_wrapper(Cli* cli, FuriString* args, void* context);
|
||||
|
||||
// #define INPUT_DEBUG
|
||||
|
||||
@@ -79,12 +79,6 @@ const char* input_get_type_name(InputType type) {
|
||||
}
|
||||
}
|
||||
|
||||
#include <cli/cli_i.h>
|
||||
|
||||
static void input_cli_wrapper(Cli* cli, FuriString* args, void* context) {
|
||||
cli_plugin_wrapper("input", cli, args, context);
|
||||
}
|
||||
|
||||
int32_t input_srv(void* p) {
|
||||
UNUSED(p);
|
||||
|
||||
@@ -102,8 +96,6 @@ int32_t input_srv(void* p) {
|
||||
#ifdef SRV_CLI
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "input", CliCommandFlagParallelSafe, input_cli_wrapper, event_pubsub);
|
||||
#else
|
||||
UNUSED(input_cli_wrapper);
|
||||
#endif
|
||||
|
||||
InputPinState pin_states[input_pins_count];
|
||||
|
||||
@@ -226,15 +226,5 @@ void input_cli(Cli* cli, FuriString* args, void* context) {
|
||||
furi_string_free(cmd);
|
||||
}
|
||||
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include <cli/cli_i.h>
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
.appid = CLI_PLUGIN_APP_ID,
|
||||
.ep_api_version = CLI_PLUGIN_API_VERSION,
|
||||
.entry_point = &input_cli,
|
||||
};
|
||||
|
||||
const FlipperAppPluginDescriptor* input_cli_plugin_ep(void) {
|
||||
return &plugin_descriptor;
|
||||
}
|
||||
CLI_PLUGIN_WRAPPER("input", input_cli)
|
||||
|
||||
@@ -141,15 +141,15 @@ static void loader_cli(Cli* cli, FuriString* args, void* context) {
|
||||
furi_record_close(RECORD_LOADER);
|
||||
}
|
||||
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include <cli/cli_i.h>
|
||||
CLI_PLUGIN_WRAPPER("loader", loader_cli)
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
.appid = CLI_PLUGIN_APP_ID,
|
||||
.ep_api_version = CLI_PLUGIN_API_VERSION,
|
||||
.entry_point = &loader_cli,
|
||||
};
|
||||
|
||||
const FlipperAppPluginDescriptor* loader_cli_plugin_ep(void) {
|
||||
return &plugin_descriptor;
|
||||
void loader_on_system_start(void) {
|
||||
#ifdef SRV_CLI
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli_wrapper, NULL);
|
||||
furi_record_close(RECORD_CLI);
|
||||
#else
|
||||
UNUSED(loader_cli);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#include <cli/cli_i.h>
|
||||
#include "loader.h"
|
||||
|
||||
static void loader_cli_wrapper(Cli* cli, FuriString* args, void* context) {
|
||||
cli_plugin_wrapper("loader", cli, args, context);
|
||||
}
|
||||
|
||||
void loader_on_system_start(void) {
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli_wrapper, NULL);
|
||||
furi_record_close(RECORD_CLI);
|
||||
}
|
||||
@@ -108,15 +108,17 @@ void power_cli(Cli* cli, FuriString* args, void* context) {
|
||||
furi_string_free(cmd);
|
||||
}
|
||||
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include <cli/cli_i.h>
|
||||
CLI_PLUGIN_WRAPPER("power", power_cli)
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
.appid = CLI_PLUGIN_APP_ID,
|
||||
.ep_api_version = CLI_PLUGIN_API_VERSION,
|
||||
.entry_point = &power_cli,
|
||||
};
|
||||
void power_on_system_start(void) {
|
||||
#ifdef SRV_CLI
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
|
||||
const FlipperAppPluginDescriptor* power_cli_plugin_ep(void) {
|
||||
return &plugin_descriptor;
|
||||
cli_add_command(cli, "power", CliCommandFlagParallelSafe, power_cli_wrapper, NULL);
|
||||
|
||||
furi_record_close(RECORD_CLI);
|
||||
#else
|
||||
UNUSED(power_cli);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#include <cli/cli_i.h>
|
||||
|
||||
static void power_cli_wrapper(Cli* cli, FuriString* args, void* context) {
|
||||
cli_plugin_wrapper("power", cli, args, context);
|
||||
}
|
||||
|
||||
void power_on_system_start(void) {
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "power", CliCommandFlagParallelSafe, power_cli_wrapper, NULL);
|
||||
furi_record_close(RECORD_CLI);
|
||||
}
|
||||
@@ -25,7 +25,7 @@ App(
|
||||
appid="js_cli",
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="js_cli_plugin_ep",
|
||||
entry_point="js_cli_execute_plugin_ep",
|
||||
requires=["cli"],
|
||||
sources=[
|
||||
"js_app.c",
|
||||
@@ -41,8 +41,8 @@ App(
|
||||
appid="js_app_start",
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
entry_point="js_app_on_system_start",
|
||||
sources=["js_start.c"],
|
||||
order=160,
|
||||
sources=["js_app.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
|
||||
@@ -204,15 +204,13 @@ void js_cli_execute(Cli* cli, FuriString* args, void* context) {
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include <cli/cli_i.h>
|
||||
CLI_PLUGIN_WRAPPER("js", js_cli_execute)
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
.appid = CLI_PLUGIN_APP_ID,
|
||||
.ep_api_version = CLI_PLUGIN_API_VERSION,
|
||||
.entry_point = &js_cli_execute,
|
||||
};
|
||||
|
||||
const FlipperAppPluginDescriptor* js_cli_plugin_ep(void) {
|
||||
return &plugin_descriptor;
|
||||
void js_app_on_system_start(void) {
|
||||
#ifdef SRV_CLI
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "js", CliCommandFlagDefault, js_cli_execute_wrapper, NULL);
|
||||
furi_record_close(RECORD_CLI);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#include <cli/cli_i.h>
|
||||
|
||||
static void js_cli_execute_wrapper(Cli* cli, FuriString* args, void* context) {
|
||||
cli_plugin_wrapper("js", cli, args, context);
|
||||
}
|
||||
|
||||
void js_app_on_system_start(void) {
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "js", CliCommandFlagDefault, js_cli_execute_wrapper, NULL);
|
||||
furi_record_close(RECORD_CLI);
|
||||
}
|
||||
Reference in New Issue
Block a user