mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-24 05:34:45 -07:00
[FL-3569] NFC CLI commands (#4158)
* 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 completions * more key combos * commands in fals * move commands out of flash * ci: fix errors * speedup cli file transfer * merge fixups * fix f18 * 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 * Now cli_shell can be customized with another motd and another command set * Added custom motd callback definition * Now user can alloc and free his own cli command set * cli_vcp can now restart shell with another command set * Help command modified to show available commands from different command sets * Api adjustement * Reworked nfc_cli to start new shell with another command set * Revert custom shell changes from vcp * Custom motd callback moved to cli_shell * Cli Shell now can be started from ongoing cli command * Help command moved to a separate function so it can be used for custom shell * Now nfc command spawns separate shell for further nfc commands * cli_shell: give up pipe to command thread * fix formatting * cli_shell: separate into toolbox * speaker_debug: fix * fix: format * Merge branch 'portasynthinca3/3928-3929-cli-fals-threads' into portasynthinca3/3965-cli_shell-toolbox * fix merge * fix. merge. * fix formatting * fix: cmd flags * fix: formatting * Added basic command descriptor structs and macros * Basic nfc commands definitions added * Nfc cli commands collection and functions added * Raw skeleton of nfc cli processor added * cli: increase default stack depth * New callbacks for ctx alloc / free added * nfc_cli moved to cli folder * Some more logic for command processor * Scanner command no works via command_processor * plugin manifest adj * Argument descriptors were removed, now only keys left * Some helper command function implemented * Command processor logic now mostly works * Added all parsers and dummy implementation of raw cmd * Now processor checks duplicated keys and treat them as errors * Some renamings * Arguments processing moved to separate function * Now command processor can reuse context of previuos command for the next one if it's allowed * can_reuse callback added for checking if context can be reused * command processor is now freed on nfc cli exit * Some cleanups * First working version of raw command * Now input data are placed directly to bit buffer * Added tag * Introduced request/response structs * Moved raw command to a separate folder * Moved some common types to header * Added protocol specific handlers for iso14a and felica * Opened felica crc header for referencing * Added handler for iso14443_3b * Opened iso15693_3_poller for referencing * Added iso15693_3 handler for raw command * NfcCliRawError enum introduced for response result * Refactored handlers implementation * Formatting functions now added as helpers * New printing result logic * Not present error value added to enum * Timeout added to raw command * Command processor now supports multivalue keys * Apdu command implementation added * NfcScanner moved to helpers and command now uses it * Helper now can format protocol names * Dump command added * Added some more functions to scanner helper * Dump main logic simplified * Dump handlers moved to protocols folder * Protocol parser added to simplify searching protocol by name * Protocol and key arguments added to dump command * Cleanups * Apdu now parses protocol using helper parser * Raw now parses protocol using helper parser * Wrong naming fix * Emulate command added to cli * Description added to action descriptor and command macros * Description field added to all commands * Removed unnecessary enum for commands * Added functions for formatting command and action info * Proper error messages and help added * Fix for unsupported single action command * Function renamed to more appropriate * Field command moved to all other commands * Cleanups * Nfc commands modified with new cli shell * Removed previous nfc_cli.c after merge * Removed nfc_cli.h header * Some renamings and cleanups * Some comments and instructions added * Some comments and instructions added * TODOs removed * Fix for missing parse callback * Added not implemented dummy for mfu actions, for now * Fix name mismatch * Remove unneeded header * Mfu command moved to separate folder, also raw info action logic added * Dictionary with id/vendors added to assets. It is used by nfc_cli_mfu_info_get_vendor function * One more unneeded header removed * Moved mfu info action to a separate file * Info action now uses sync mfu poller * mfu rdbl action added * wrbl action added for mfu command * Some formatting for rdbl command * Function for formatting mfu errors added * All mfu actions now show errors in the same way * Fix error with sync poller. Previously when read failed function returned ErrorNone, now it processes iso14a error to get proper value * Make PVS happy * Nfc cli now doesn't start if desktop app is running * Make action description look more common * Scanner now has -t key and can show detected protocol hierarchies * Apdu now checks max input payload data * Proper format * Proper error handling added to dump command * Timeout key added dump command * Fix merge issue * formatting * Pragma pack replaced with FURI_PACKED * Fix felica memory leak --------- Co-authored-by: Anna Antonenko <portasynthinca3@gmail.com> Co-authored-by: Georgii Surkov <georgii.surkov@outlook.com> Co-authored-by: あく <alleteam@gmail.com> Co-authored-by: hedger <hedger@users.noreply.github.com> Co-authored-by: hedger <hedger@nanode.su>
This commit is contained in:
227
applications/main/nfc/cli/commands/mfu/nfc_cli_action_info.c
Normal file
227
applications/main/nfc/cli/commands/mfu/nfc_cli_action_info.c
Normal file
@@ -0,0 +1,227 @@
|
||||
|
||||
#include "nfc_cli_action_info.h"
|
||||
|
||||
#include "../../../helpers/protocol_support/mf_ultralight/mf_ultralight_render.h"
|
||||
#include "../helpers/nfc_cli_format.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include <storage/storage.h>
|
||||
#include <nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h>
|
||||
|
||||
#define TAG "INFO"
|
||||
|
||||
typedef struct {
|
||||
uint8_t magic;
|
||||
union {
|
||||
uint8_t value;
|
||||
struct {
|
||||
uint8_t minor : 4;
|
||||
uint8_t major : 4;
|
||||
};
|
||||
} version;
|
||||
|
||||
uint8_t size;
|
||||
|
||||
union {
|
||||
uint8_t value;
|
||||
struct {
|
||||
uint8_t write : 4;
|
||||
uint8_t read : 4;
|
||||
};
|
||||
} access;
|
||||
} FURI_PACKED MfUltralightCapabilityContainer;
|
||||
|
||||
typedef struct {
|
||||
Nfc* nfc;
|
||||
MfUltralightData* data;
|
||||
} NfcCliMfuContext;
|
||||
|
||||
static void nfc_cli_mfu_info_get_vendor(const uint8_t vendor_key, FuriString* output) {
|
||||
furi_assert(output);
|
||||
|
||||
FuriString* buf = furi_string_alloc();
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* ff = flipper_format_file_alloc(storage);
|
||||
|
||||
do {
|
||||
if(!flipper_format_file_open_existing(ff, EXT_PATH("nfc/assets/vendors.nfc"))) {
|
||||
FURI_LOG_W(TAG, "NFC Vendors dict not found");
|
||||
break;
|
||||
}
|
||||
|
||||
char uid_str[5];
|
||||
snprintf(uid_str, sizeof(uid_str), "%d", vendor_key);
|
||||
|
||||
if(flipper_format_read_string(ff, uid_str, buf))
|
||||
furi_string_printf(output, "%s, %s", uid_str, furi_string_get_cstr(buf));
|
||||
else
|
||||
furi_string_printf(output, "unknown");
|
||||
} while(false);
|
||||
|
||||
flipper_format_free(ff);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
furi_string_free(buf);
|
||||
}
|
||||
|
||||
const char*
|
||||
nfc_cli_mfu_capability_container_get_access_description(const uint8_t value, bool read) {
|
||||
const char* description = "RFU"; //value 0x01 - 0x07, and 0xF when read
|
||||
if(value == 0x00)
|
||||
description = "access fully granted";
|
||||
else if(value >= 0x08 && value <= 0x0E)
|
||||
description = "proprietary";
|
||||
else if(value == 0x0F && !read)
|
||||
description = "no access granted at all";
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
static void nfc_cli_mfu_info_print_common(const MfUltralightData* data) {
|
||||
FuriString* str = furi_string_alloc();
|
||||
|
||||
printf(ANSI_FG_GREEN "\r\n\tTag information\r\n" ANSI_RESET);
|
||||
printf(
|
||||
"Type: " ANSI_FG_YELLOW "%s\r\n" ANSI_RESET,
|
||||
mf_ultralight_get_device_name(data, NfcDeviceNameTypeFull));
|
||||
|
||||
nfc_cli_mfu_info_get_vendor(data->iso14443_3a_data->uid[0], str);
|
||||
printf("Vendor ID: %s\r\n", furi_string_get_cstr(str));
|
||||
|
||||
furi_string_reset(str);
|
||||
nfc_render_mf_ultralight_info(data, NfcProtocolFormatTypeFull, str);
|
||||
printf("%s\r\n", furi_string_get_cstr(str));
|
||||
printf("BCC0: %02X\r\nBCC1: %02X\r\n", data->page[0].data[3], data->page[2].data[0]);
|
||||
|
||||
furi_string_free(str);
|
||||
}
|
||||
|
||||
static void nfc_cli_mfu_info_print_ndef(const MfUltralightData* data) {
|
||||
const MfUltralightCapabilityContainer* cc =
|
||||
(const MfUltralightCapabilityContainer*)data->page[3].data;
|
||||
if(cc->magic == 0xE1) {
|
||||
printf(ANSI_FG_GREEN "\r\n\tNDEF Message\r\n" ANSI_RESET);
|
||||
nfc_cli_printf_array(data->page[3].data, 4, "Capability container: ");
|
||||
printf(
|
||||
"\r\nMagic number: %02X\r\nVersion %d.%d\r\nSize: [%02X] - %d bytes\r\n",
|
||||
cc->magic,
|
||||
cc->version.major,
|
||||
cc->version.minor,
|
||||
cc->size,
|
||||
cc->size * 8);
|
||||
printf(
|
||||
"Access read: [%02X] - %s",
|
||||
cc->access.read,
|
||||
nfc_cli_mfu_capability_container_get_access_description(cc->access.read, true));
|
||||
printf(
|
||||
"Access write: [%02X] - %s",
|
||||
cc->access.write,
|
||||
nfc_cli_mfu_capability_container_get_access_description(cc->access.write, false));
|
||||
}
|
||||
}
|
||||
|
||||
static void nfc_cli_mfu_info_print_counter(const MfUltralightData* data) {
|
||||
uint32_t features = mf_ultralight_get_feature_support_set(data->type);
|
||||
if(!mf_ultralight_support_feature(features, MfUltralightFeatureSupportReadCounter)) return;
|
||||
|
||||
printf(ANSI_FG_GREEN "\r\n\n\tTag counters\r\n" ANSI_RESET);
|
||||
uint8_t i =
|
||||
mf_ultralight_support_feature(features, MfUltralightFeatureSupportSingleCounter) ? 2 : 0;
|
||||
|
||||
for(; i < MF_ULTRALIGHT_COUNTER_NUM; i++) {
|
||||
printf("Counter [%d]: ", i);
|
||||
nfc_cli_printf_array(data->counter[i].data, MF_ULTRALIGHT_COUNTER_SIZE, "");
|
||||
printf(" Value: %lu\r\n", data->counter[i].counter);
|
||||
|
||||
const uint8_t tf = data->tearing_flag[i].data;
|
||||
printf(
|
||||
"Tearing [%d]: [%02X] %s",
|
||||
i,
|
||||
tf,
|
||||
tf == MF_ULTRALIGHT_TEARING_FLAG_DEFAULT ? "(ok)" : "");
|
||||
}
|
||||
}
|
||||
|
||||
static void nfc_cli_mfu_info_print_signature(const MfUltralightData* data) {
|
||||
uint32_t features = mf_ultralight_get_feature_support_set(data->type);
|
||||
if(!mf_ultralight_support_feature(features, MfUltralightFeatureSupportReadSignature)) return;
|
||||
|
||||
const MfUltralightSignature* signature = &data->signature;
|
||||
printf(ANSI_FG_GREEN "\r\n\n\tTag signature\r\n" ANSI_RESET);
|
||||
nfc_cli_printf_array(signature->data, sizeof(signature->data), "ECC signature: ");
|
||||
}
|
||||
|
||||
static void nfc_cli_mfu_info_print_version_storage_size(uint8_t storage_size) {
|
||||
uint16_t max_size = 1 << ((storage_size >> 1) + 1);
|
||||
uint16_t min_exact_size = 1 << (storage_size >> 1);
|
||||
|
||||
bool exact_size = !(storage_size & 0x01);
|
||||
if(exact_size)
|
||||
printf("[%02X], (%u bytes)", storage_size, min_exact_size);
|
||||
else
|
||||
printf("[%02X], (%u <-> %u bytes)", storage_size, min_exact_size, max_size);
|
||||
}
|
||||
|
||||
static void nfc_cli_mfu_info_print_version(const MfUltralightData* data) {
|
||||
uint32_t features = mf_ultralight_get_feature_support_set(data->type);
|
||||
if(!mf_ultralight_support_feature(features, MfUltralightFeatureSupportReadVersion)) return;
|
||||
|
||||
const MfUltralightVersion* version = &data->version;
|
||||
printf(ANSI_FG_GREEN "\r\n\n\tTag Version\r\n" ANSI_RESET);
|
||||
nfc_cli_printf_array((uint8_t*)version, sizeof(MfUltralightVersion), "Raw bytes: ");
|
||||
|
||||
FuriString* str = furi_string_alloc();
|
||||
nfc_cli_mfu_info_get_vendor(version->vendor_id, str);
|
||||
printf("\r\nVendor ID: %s\r\n", furi_string_get_cstr(str));
|
||||
furi_string_free(str);
|
||||
|
||||
printf("Product type: %02X\r\n", version->prod_type);
|
||||
|
||||
printf(
|
||||
"Protocol type: %02X%s\r\n",
|
||||
version->protocol_type,
|
||||
(version->protocol_type == 0x3) ? ", ISO14443-3 Compliant" : "");
|
||||
|
||||
printf(
|
||||
"Product subtype: [%02X], %s\r\n",
|
||||
version->prod_subtype,
|
||||
(version->prod_subtype == 1) ? "17 pF" : "50pF");
|
||||
printf(
|
||||
"Major version: %02X\r\nMinor version: %02X\r\nSize: ",
|
||||
version->prod_ver_major,
|
||||
version->prod_ver_minor);
|
||||
nfc_cli_mfu_info_print_version_storage_size(version->storage_size);
|
||||
}
|
||||
|
||||
NfcCliActionContext* nfc_cli_mfu_info_alloc_ctx(Nfc* nfc) {
|
||||
NfcCliMfuContext* instance = malloc(sizeof(NfcCliMfuContext));
|
||||
instance->nfc = nfc;
|
||||
instance->data = mf_ultralight_alloc();
|
||||
return instance;
|
||||
}
|
||||
|
||||
void nfc_cli_mfu_info_free_ctx(NfcCliActionContext* ctx) {
|
||||
NfcCliMfuContext* instance = ctx;
|
||||
mf_ultralight_free(instance->data);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void nfc_cli_mfu_info_execute(PipeSide* pipe, NfcCliActionContext* ctx) {
|
||||
furi_assert(pipe);
|
||||
furi_assert(ctx);
|
||||
|
||||
NfcCliMfuContext* instance = ctx;
|
||||
|
||||
MfUltralightError error =
|
||||
mf_ultralight_poller_sync_read_card(instance->nfc, instance->data, NULL);
|
||||
if(error == MfUltralightErrorNone) {
|
||||
const MfUltralightData* data = instance->data;
|
||||
nfc_cli_mfu_info_print_common(data);
|
||||
nfc_cli_mfu_info_print_ndef(data);
|
||||
nfc_cli_mfu_info_print_counter(data);
|
||||
nfc_cli_mfu_info_print_signature(data);
|
||||
nfc_cli_mfu_info_print_version(data);
|
||||
} else {
|
||||
printf(ANSI_FG_RED "Error: %s" ANSI_RESET, nfc_cli_mf_ultralight_get_error(error));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../nfc_cli_command_base_i.h"
|
||||
|
||||
NfcCliActionContext* nfc_cli_mfu_info_alloc_ctx(Nfc* nfc);
|
||||
void nfc_cli_mfu_info_free_ctx(NfcCliActionContext* ctx);
|
||||
void nfc_cli_mfu_info_execute(PipeSide* pipe, NfcCliActionContext* ctx);
|
||||
52
applications/main/nfc/cli/commands/mfu/nfc_cli_action_rdbl.c
Normal file
52
applications/main/nfc/cli/commands/mfu/nfc_cli_action_rdbl.c
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "nfc_cli_action_rdbl.h"
|
||||
|
||||
#include "../helpers/nfc_cli_format.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <toolbox/strint.h>
|
||||
#include <nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h>
|
||||
|
||||
#define MF_ULTRALIGHT_POLLER_COMPLETE_EVENT (1UL << 0)
|
||||
|
||||
typedef struct {
|
||||
Nfc* nfc;
|
||||
uint16_t block;
|
||||
} NfcCliMfuRdblContext;
|
||||
|
||||
NfcCliActionContext* nfc_cli_mfu_rdbl_alloc_ctx(Nfc* nfc) {
|
||||
furi_assert(nfc);
|
||||
NfcCliMfuRdblContext* instance = malloc(sizeof(NfcCliMfuRdblContext));
|
||||
instance->nfc = nfc;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void nfc_cli_mfu_rdbl_free_ctx(NfcCliActionContext* ctx) {
|
||||
furi_assert(ctx);
|
||||
NfcCliMfuRdblContext* instance = ctx;
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void nfc_cli_mfu_rdbl_execute(PipeSide* pipe, NfcCliActionContext* ctx) {
|
||||
furi_assert(pipe);
|
||||
|
||||
NfcCliMfuRdblContext* instance = ctx;
|
||||
MfUltralightPage page = {0};
|
||||
|
||||
MfUltralightError error =
|
||||
mf_ultralight_poller_sync_read_page(instance->nfc, instance->block, &page);
|
||||
|
||||
if(error == MfUltralightErrorNone) {
|
||||
printf("\r\nBlock: %d ", instance->block);
|
||||
nfc_cli_printf_array(page.data, sizeof(MfUltralightPage), "Data: ");
|
||||
printf("\r\n");
|
||||
} else {
|
||||
printf(ANSI_FG_RED "Error: %s" ANSI_RESET, nfc_cli_mf_ultralight_get_error(error));
|
||||
}
|
||||
}
|
||||
|
||||
bool nfc_cli_mfu_rdbl_parse_block(FuriString* value, NfcCliActionContext* output) {
|
||||
NfcCliMfuRdblContext* ctx = output;
|
||||
|
||||
StrintParseError err = strint_to_uint16(furi_string_get_cstr(value), NULL, &ctx->block, 10);
|
||||
return err == StrintParseNoError;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../nfc_cli_command_base_i.h"
|
||||
|
||||
NfcCliActionContext* nfc_cli_mfu_rdbl_alloc_ctx(Nfc* nfc);
|
||||
void nfc_cli_mfu_rdbl_free_ctx(NfcCliActionContext* ctx);
|
||||
void nfc_cli_mfu_rdbl_execute(PipeSide* pipe, NfcCliActionContext* ctx);
|
||||
bool nfc_cli_mfu_rdbl_parse_block(FuriString* value, NfcCliActionContext* ctx);
|
||||
71
applications/main/nfc/cli/commands/mfu/nfc_cli_action_wrbl.c
Normal file
71
applications/main/nfc/cli/commands/mfu/nfc_cli_action_wrbl.c
Normal file
@@ -0,0 +1,71 @@
|
||||
#include "nfc_cli_action_rdbl.h"
|
||||
|
||||
#include "../helpers/nfc_cli_format.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <toolbox/args.h>
|
||||
#include <toolbox/strint.h>
|
||||
#include <nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h>
|
||||
|
||||
#define MF_ULTRALIGHT_POLLER_COMPLETE_EVENT (1UL << 0)
|
||||
|
||||
typedef struct {
|
||||
Nfc* nfc;
|
||||
uint16_t block;
|
||||
MfUltralightPage page;
|
||||
} NfcCliMfuWrblContext;
|
||||
|
||||
NfcCliActionContext* nfc_cli_mfu_wrbl_alloc_ctx(Nfc* nfc) {
|
||||
furi_assert(nfc);
|
||||
NfcCliMfuWrblContext* instance = malloc(sizeof(NfcCliMfuWrblContext));
|
||||
instance->nfc = nfc;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void nfc_cli_mfu_wrbl_free_ctx(NfcCliActionContext* ctx) {
|
||||
furi_assert(ctx);
|
||||
NfcCliMfuWrblContext* instance = ctx;
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void nfc_cli_mfu_wrbl_execute(PipeSide* pipe, NfcCliActionContext* ctx) {
|
||||
furi_assert(pipe);
|
||||
|
||||
NfcCliMfuWrblContext* instance = ctx;
|
||||
|
||||
MfUltralightError error =
|
||||
mf_ultralight_poller_sync_write_page(instance->nfc, instance->block, &instance->page);
|
||||
|
||||
if(error == MfUltralightErrorNone) {
|
||||
printf(ANSI_FG_BR_GREEN "\r\nSuccess\r\n" ANSI_RESET);
|
||||
printf("Block: %d ", instance->block);
|
||||
nfc_cli_printf_array(instance->page.data, sizeof(MfUltralightPage), "Data: ");
|
||||
printf("\r\n");
|
||||
} else {
|
||||
printf(ANSI_FG_RED "Error: %s" ANSI_RESET, nfc_cli_mf_ultralight_get_error(error));
|
||||
}
|
||||
}
|
||||
|
||||
bool nfc_cli_mfu_wrbl_parse_block(FuriString* value, NfcCliActionContext* output) {
|
||||
NfcCliMfuWrblContext* ctx = output;
|
||||
|
||||
StrintParseError err = strint_to_uint16(furi_string_get_cstr(value), NULL, &ctx->block, 10);
|
||||
return err == StrintParseNoError;
|
||||
}
|
||||
|
||||
bool nfc_cli_mfu_wrbl_parse_data(FuriString* value, void* output) {
|
||||
NfcCliMfuWrblContext* ctx = output;
|
||||
|
||||
bool result = false;
|
||||
do {
|
||||
size_t len = furi_string_size(value);
|
||||
if(len % 2 != 0) break;
|
||||
|
||||
size_t data_length = len / 2;
|
||||
if(data_length != MF_ULTRALIGHT_PAGE_SIZE) break;
|
||||
|
||||
result = args_read_hex_bytes(value, ctx->page.data, data_length);
|
||||
} while(false);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../nfc_cli_command_base_i.h"
|
||||
|
||||
NfcCliActionContext* nfc_cli_mfu_wrbl_alloc_ctx(Nfc* nfc);
|
||||
void nfc_cli_mfu_wrbl_free_ctx(NfcCliActionContext* ctx);
|
||||
void nfc_cli_mfu_wrbl_execute(PipeSide* pipe, NfcCliActionContext* ctx);
|
||||
bool nfc_cli_mfu_wrbl_parse_block(FuriString* value, NfcCliActionContext* ctx);
|
||||
bool nfc_cli_mfu_wrbl_parse_data(FuriString* value, void* output);
|
||||
77
applications/main/nfc/cli/commands/mfu/nfc_cli_command_mfu.c
Normal file
77
applications/main/nfc/cli/commands/mfu/nfc_cli_command_mfu.c
Normal file
@@ -0,0 +1,77 @@
|
||||
#include "nfc_cli_command_mfu.h"
|
||||
#include "nfc_cli_action_info.h"
|
||||
#include "nfc_cli_action_rdbl.h"
|
||||
#include "nfc_cli_action_wrbl.h"
|
||||
|
||||
#define TAG "MFU"
|
||||
|
||||
//mfu info
|
||||
const NfcCliActionDescriptor info_action = {
|
||||
.name = "info",
|
||||
.description = "Get basic information about the card",
|
||||
.alloc = nfc_cli_mfu_info_alloc_ctx,
|
||||
.free = nfc_cli_mfu_info_free_ctx,
|
||||
.execute = nfc_cli_mfu_info_execute,
|
||||
.key_count = 0,
|
||||
.keys = NULL,
|
||||
};
|
||||
|
||||
const NfcCliKeyDescriptor rdbl_action_keys[] = {
|
||||
{
|
||||
.short_name = "b",
|
||||
.long_name = "block",
|
||||
.features = {.required = true, .parameter = true},
|
||||
.description = "desired block number",
|
||||
.parse = nfc_cli_mfu_rdbl_parse_block,
|
||||
},
|
||||
};
|
||||
|
||||
//mfu rdbl -b 0
|
||||
//mfu rdbl --block 0
|
||||
const NfcCliActionDescriptor rdbl_action = {
|
||||
.name = "rdbl",
|
||||
.description = "Read block from ultralight card",
|
||||
.alloc = nfc_cli_mfu_rdbl_alloc_ctx,
|
||||
.free = nfc_cli_mfu_rdbl_free_ctx,
|
||||
.execute = nfc_cli_mfu_rdbl_execute,
|
||||
.key_count = COUNT_OF(rdbl_action_keys),
|
||||
.keys = rdbl_action_keys,
|
||||
};
|
||||
|
||||
const NfcCliKeyDescriptor wrbl_action_keys[] = {
|
||||
{
|
||||
.short_name = "b",
|
||||
.long_name = "block",
|
||||
.features = {.required = true, .parameter = true},
|
||||
.description = "desired block number",
|
||||
.parse = nfc_cli_mfu_wrbl_parse_block,
|
||||
},
|
||||
{
|
||||
.short_name = "d",
|
||||
.long_name = "data",
|
||||
.features = {.required = true, .parameter = true},
|
||||
.description = "new data for block",
|
||||
.parse = nfc_cli_mfu_wrbl_parse_data,
|
||||
},
|
||||
};
|
||||
|
||||
//mfu wrbl -b 0 -d DEADBEAF
|
||||
//mfu rdbl --block 0 -- data DEADBEEF
|
||||
const NfcCliActionDescriptor wrbl_action = {
|
||||
.name = "wrbl",
|
||||
.description = "Read block from ultralight card",
|
||||
.alloc = nfc_cli_mfu_wrbl_alloc_ctx,
|
||||
.free = nfc_cli_mfu_wrbl_free_ctx,
|
||||
.execute = nfc_cli_mfu_wrbl_execute,
|
||||
.key_count = COUNT_OF(wrbl_action_keys),
|
||||
.keys = wrbl_action_keys,
|
||||
};
|
||||
|
||||
const NfcCliActionDescriptor* mfu_actions[] = {
|
||||
&rdbl_action,
|
||||
&info_action,
|
||||
&wrbl_action,
|
||||
};
|
||||
|
||||
//Command descriptor
|
||||
ADD_NFC_CLI_COMMAND(mfu, "Mifare Ultralight specific commands", mfu_actions);
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../nfc_cli_command_base_i.h"
|
||||
|
||||
extern const NfcCliCommandDescriptor mfu_cmd;
|
||||
Reference in New Issue
Block a user