Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add nfc apdu cli command back #4133

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 163 additions & 0 deletions applications/main/nfc/nfc_cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,36 @@
#include <cli/cli.h>
#include <lib/toolbox/args.h>
#include <lib/toolbox/hex.h>
#include <lib/toolbox/bit_buffer.h>
#include <lib/nfc/nfc_poller.h>
#include <lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h>
#include <lib/nfc/protocols/iso14443_4b/iso14443_4b_poller.h>
#include <lib/nfc/protocols/iso15693_3/iso15693_3_poller.h>

#include <furi_hal_nfc.h>

#define FLAG_EVENT (1 << 10)

#define NFC_MAX_BUFFER_SIZE (256)
#define NFC_BASE_PROTOCOL_MAX (3)
#define POLLER_DONE (1 << 0)
#define POLLER_ERR (1 << 1)
static NfcProtocol BASE_PROTOCOL[NFC_BASE_PROTOCOL_MAX] = {
NfcProtocolIso14443_4a,
NfcProtocolIso14443_4b,
NfcProtocolIso15693_3};
typedef struct ApduContext {
BitBuffer* tx_buffer;
BitBuffer* rx_buffer;
bool ready;
FuriThreadId thread_id;
} ApduContext;

static void nfc_cli_print_usage(void) {
printf("Usage:\r\n");
printf("nfc <cmd>\r\n");
printf("Cmd list:\r\n");
printf("\tapdu\t - Send APDU and print response \r\n");
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
printf("\tfield\t - turn field on\r\n");
}
Expand Down Expand Up @@ -40,6 +61,144 @@ static void nfc_cli_field(Cli* cli, FuriString* args) {
furi_hal_nfc_release();
}

static NfcCommand trx_callback(NfcGenericEvent event, void* context) {
furi_check(context);
ApduContext* apdu_context = (ApduContext*)context;

if(apdu_context->ready) {
apdu_context->ready = false;
if(NfcProtocolIso14443_4a == event.protocol) {
Iso14443_4aError err = iso14443_4a_poller_send_block(
event.instance, apdu_context->tx_buffer, apdu_context->rx_buffer);
if(Iso14443_4aErrorNone == err) {
furi_thread_flags_set(apdu_context->thread_id, POLLER_DONE);
return NfcCommandContinue;
} else {
furi_thread_flags_set(apdu_context->thread_id, POLLER_ERR);
return NfcCommandStop;
}
} else if(NfcProtocolIso14443_4b == event.protocol) {
Iso14443_4bError err = iso14443_4b_poller_send_block(
event.instance, apdu_context->tx_buffer, apdu_context->rx_buffer);
if(Iso14443_4bErrorNone == err) {
furi_thread_flags_set(apdu_context->thread_id, POLLER_DONE);
return NfcCommandContinue;
} else {
furi_thread_flags_set(apdu_context->thread_id, POLLER_ERR);
return NfcCommandStop;
}
} else if(NfcProtocolIso15693_3 == event.protocol) {
Iso15693_3Error err = iso15693_3_poller_send_frame(
event.instance,
apdu_context->tx_buffer,
apdu_context->rx_buffer,
ISO15693_3_FDT_POLL_FC);
if(Iso15693_3ErrorNone == err) {
furi_thread_flags_set(apdu_context->thread_id, POLLER_DONE);
return NfcCommandContinue;
} else {
furi_thread_flags_set(apdu_context->thread_id, POLLER_ERR);
return NfcCommandStop;
}
} else {
// should never reach here
furi_crash("Unknown protocol");
}
} else {
furi_delay_ms(100);
}

return NfcCommandContinue;
}

static void nfc_cli_apdu(Cli* cli, FuriString* args) {
UNUSED(cli);
Nfc* nfc = NULL;
NfcPoller* poller = NULL;
FuriString* data = furi_string_alloc();
uint8_t* req_buffer = NULL;
uint8_t* resp_buffer = NULL;
size_t apdu_size = 0;
size_t resp_size = 0;
NfcProtocol current_protocol = NfcProtocolInvalid;

do {
if(0 == args_get_first_word_length(args)) {
printf(
"Use like `nfc apdu 00a404000e325041592e5359532e444446303100 00a4040008a0000003010102` \r\n");
break;
}
nfc = nfc_alloc();

printf("detecting tag\r\n");
for(int i = 0; i < NFC_BASE_PROTOCOL_MAX; i++) {
poller = nfc_poller_alloc(nfc, BASE_PROTOCOL[i]);
bool is_detected = nfc_poller_detect(poller);
nfc_poller_free(poller);
if(is_detected) {
current_protocol = BASE_PROTOCOL[i];
printf("detected tag:%d\r\n", BASE_PROTOCOL[i]);
break;
}
}
if(NfcProtocolInvalid == current_protocol) {
nfc_free(nfc);
printf("Can not find any tag\r\n");
break;
}
poller = nfc_poller_alloc(nfc, current_protocol);
ApduContext* apdu_context = malloc(sizeof(ApduContext));
apdu_context->tx_buffer = bit_buffer_alloc(NFC_MAX_BUFFER_SIZE);
apdu_context->rx_buffer = bit_buffer_alloc(NFC_MAX_BUFFER_SIZE);
apdu_context->ready = false;
apdu_context->thread_id = furi_thread_get_current_id();

nfc_poller_start(poller, trx_callback, apdu_context);
while(args_read_string_and_trim(args, data)) {
bit_buffer_reset(apdu_context->tx_buffer);
bit_buffer_reset(apdu_context->rx_buffer);
apdu_size = furi_string_size(data) / 2;
req_buffer = malloc(apdu_size);

hex_chars_to_uint8(furi_string_get_cstr(data), req_buffer);
printf("Sending APDU:%s to Tag\r\n", furi_string_get_cstr(data));
bit_buffer_copy_bytes(apdu_context->tx_buffer, req_buffer, apdu_size);
apdu_context->ready = true;
uint32_t flags = furi_thread_flags_wait(POLLER_DONE, FuriFlagWaitAny, 3000);
if(0 == (flags & POLLER_DONE)) {
printf("Error or Timeout");
free(req_buffer);
break;
}
furi_assert(apdu_context->ready == false);
resp_size = bit_buffer_get_size_bytes(apdu_context->rx_buffer) * 2;
if(!resp_size) {
printf("No response\r\n");
free(req_buffer);
continue;
}
resp_buffer = malloc(resp_size);
uint8_to_hex_chars(
bit_buffer_get_data(apdu_context->rx_buffer), resp_buffer, resp_size);
resp_buffer[resp_size] = 0;
printf("Response: %s\r\n", resp_buffer);

free(req_buffer);
free(resp_buffer);
}

nfc_poller_stop(poller);
nfc_poller_free(poller);
nfc_free(nfc);

bit_buffer_free(apdu_context->tx_buffer);
bit_buffer_free(apdu_context->rx_buffer);
free(apdu_context);
} while(false);

furi_string_free(data);
}

static void nfc_cli(Cli* cli, FuriString* args, void* context) {
UNUSED(context);
FuriString* cmd;
Expand All @@ -50,6 +209,10 @@ static void nfc_cli(Cli* cli, FuriString* args, void* context) {
nfc_cli_print_usage();
break;
}
if(furi_string_cmp_str(cmd, "apdu") == 0) {
nfc_cli_apdu(cli, args);
break;
}
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
if(furi_string_cmp_str(cmd, "field") == 0) {
nfc_cli_field(cli, args);
Expand Down