mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 04:34:43 +04:00
573 lines
20 KiB
C
573 lines
20 KiB
C
#include "felica_poller_i.h"
|
|
#include <mlib/m-array.h>
|
|
#include <mlib/m-core.h>
|
|
|
|
#include <nfc/protocols/nfc_poller_base.h>
|
|
|
|
#include <furi.h>
|
|
#include <furi_hal.h>
|
|
|
|
#define TAG "FelicaPoller"
|
|
|
|
ARRAY_DEF(felica_service_array, FelicaService, M_POD_OPLIST); // -V658
|
|
ARRAY_DEF(felica_area_array, FelicaArea, M_POD_OPLIST); // -V658
|
|
ARRAY_DEF(felica_public_block_array, FelicaPublicBlock, M_POD_OPLIST); // -V658
|
|
ARRAY_DEF(felica_system_array, FelicaSystem, M_POD_OPLIST); // -V658
|
|
|
|
typedef NfcCommand (*FelicaPollerReadHandler)(FelicaPoller* instance);
|
|
|
|
const FelicaData* felica_poller_get_data(FelicaPoller* instance) {
|
|
furi_assert(instance);
|
|
furi_assert(instance->data);
|
|
|
|
return instance->data;
|
|
}
|
|
|
|
static FelicaPoller* felica_poller_alloc(Nfc* nfc) {
|
|
furi_assert(nfc);
|
|
|
|
FelicaPoller* instance = malloc(sizeof(FelicaPoller));
|
|
instance->nfc = nfc;
|
|
instance->tx_buffer = bit_buffer_alloc(FELICA_POLLER_MAX_BUFFER_SIZE);
|
|
instance->rx_buffer = bit_buffer_alloc(FELICA_POLLER_MAX_BUFFER_SIZE);
|
|
|
|
nfc_config(instance->nfc, NfcModePoller, NfcTechFelica);
|
|
nfc_set_guard_time_us(instance->nfc, FELICA_GUARD_TIME_US);
|
|
nfc_set_fdt_poll_fc(instance->nfc, FELICA_FDT_POLL_FC);
|
|
nfc_set_fdt_poll_poll_us(instance->nfc, FELICA_POLL_POLL_MIN_US);
|
|
|
|
mbedtls_des3_init(&instance->auth.des_context);
|
|
instance->data = felica_alloc();
|
|
|
|
instance->felica_event.data = &instance->felica_event_data;
|
|
instance->general_event.protocol = NfcProtocolFelica;
|
|
instance->general_event.event_data = &instance->felica_event;
|
|
instance->general_event.instance = instance;
|
|
|
|
instance->systems_read = 0;
|
|
instance->systems_total = 0;
|
|
|
|
return instance;
|
|
}
|
|
|
|
static void felica_poller_free(FelicaPoller* instance) {
|
|
furi_assert(instance);
|
|
|
|
furi_assert(instance->tx_buffer);
|
|
furi_assert(instance->rx_buffer);
|
|
furi_assert(instance->data);
|
|
|
|
mbedtls_des3_free(&instance->auth.des_context);
|
|
bit_buffer_free(instance->tx_buffer);
|
|
bit_buffer_free(instance->rx_buffer);
|
|
felica_free(instance->data);
|
|
free(instance);
|
|
}
|
|
|
|
static void
|
|
felica_poller_set_callback(FelicaPoller* instance, NfcGenericCallback callback, void* context) {
|
|
furi_assert(instance);
|
|
furi_assert(callback);
|
|
|
|
instance->callback = callback;
|
|
instance->context = context;
|
|
}
|
|
|
|
NfcCommand felica_poller_state_handler_idle(FelicaPoller* instance) {
|
|
FURI_LOG_D(TAG, "Idle");
|
|
felica_reset(instance->data);
|
|
instance->state = FelicaPollerStateActivated;
|
|
|
|
return NfcCommandContinue;
|
|
}
|
|
|
|
NfcCommand felica_poller_state_handler_activate(FelicaPoller* instance) {
|
|
FURI_LOG_D(TAG, "Activate");
|
|
|
|
NfcCommand command = NfcCommandContinue;
|
|
|
|
FelicaError error = felica_poller_activate(instance, instance->data);
|
|
if(error == FelicaErrorNone) {
|
|
furi_hal_random_fill_buf(instance->data->data.fs.rc.data, FELICA_DATA_BLOCK_SIZE);
|
|
felica_get_workflow_type(instance->data);
|
|
|
|
instance->felica_event.type = FelicaPollerEventTypeRequestAuthContext;
|
|
instance->felica_event_data.auth_context = &instance->auth.context;
|
|
|
|
instance->callback(instance->general_event, instance->context);
|
|
|
|
switch(instance->data->workflow_type) {
|
|
case FelicaStandard:
|
|
instance->state = FelicaPollerStateListSystem;
|
|
break;
|
|
case FelicaLite:
|
|
instance->state = FelicaPollerStateReadLiteBlocks;
|
|
break;
|
|
default:
|
|
// Unimplemented
|
|
instance->state = FelicaPollerStateReadSuccess;
|
|
break;
|
|
}
|
|
|
|
bool skip_auth = instance->auth.context.skip_auth;
|
|
if(!skip_auth) {
|
|
instance->state = FelicaPollerStateAuthenticateInternal;
|
|
}
|
|
} else if(error != FelicaErrorTimeout) {
|
|
instance->felica_event.type = FelicaPollerEventTypeError;
|
|
instance->felica_event_data.error = error;
|
|
instance->state = FelicaPollerStateReadFailed;
|
|
}
|
|
return command;
|
|
}
|
|
|
|
NfcCommand felica_poller_state_handler_list_system(FelicaPoller* instance) {
|
|
FURI_LOG_D(TAG, "List System");
|
|
|
|
NfcCommand command = NfcCommandContinue;
|
|
|
|
FelicaListSystemCodeCommandResponse* response_system_code;
|
|
FelicaError error = felica_poller_list_system_code(instance, &response_system_code);
|
|
|
|
instance->systems_total = response_system_code->system_count;
|
|
simple_array_init(instance->data->systems, instance->systems_total);
|
|
uint8_t* system_codes = response_system_code->system_code;
|
|
|
|
for(uint8_t i = 0; i < instance->systems_total; i++) {
|
|
FelicaSystem* system = simple_array_get(instance->data->systems, i);
|
|
system->system_code = system_codes[i * 2] << 8 | system_codes[i * 2 + 1];
|
|
system->system_code_idx = i;
|
|
}
|
|
|
|
if(error == FelicaErrorNone) {
|
|
instance->state = FelicaPollerStateSelectSystemIndex;
|
|
} else if(error != FelicaErrorTimeout) {
|
|
instance->felica_event.type = FelicaPollerEventTypeError;
|
|
instance->felica_event_data.error = error;
|
|
instance->state = FelicaPollerStateReadFailed;
|
|
}
|
|
return command;
|
|
}
|
|
|
|
NfcCommand felica_poller_state_handler_select_system_idx(FelicaPoller* instance) {
|
|
FURI_LOG_D(TAG, "Select System Index %d", instance->systems_read);
|
|
uint8_t system_index_mask = instance->systems_read << 4;
|
|
instance->data->idm.data[0] &= 0x0F;
|
|
instance->data->idm.data[0] |= system_index_mask;
|
|
instance->state = FelicaPollerStateTraverseStandardSystem;
|
|
|
|
return NfcCommandContinue;
|
|
}
|
|
|
|
NfcCommand felica_poller_state_handler_auth_internal(FelicaPoller* instance) {
|
|
FURI_LOG_D(TAG, "Auth Internal");
|
|
|
|
felica_calculate_session_key(
|
|
&instance->auth.des_context,
|
|
instance->auth.context.card_key.data,
|
|
instance->data->data.fs.rc.data,
|
|
instance->auth.session_key.data);
|
|
|
|
switch(instance->data->workflow_type) {
|
|
case FelicaStandard:
|
|
instance->state = FelicaPollerStateTraverseStandardSystem;
|
|
break;
|
|
case FelicaLite:
|
|
instance->state = FelicaPollerStateReadLiteBlocks;
|
|
break;
|
|
default:
|
|
// Unimplemented
|
|
instance->state = FelicaPollerStateReadSuccess;
|
|
break;
|
|
}
|
|
|
|
uint8_t blocks[3] = {FELICA_BLOCK_INDEX_RC, 0, 0};
|
|
FelicaPollerWriteCommandResponse* tx_resp;
|
|
do {
|
|
FelicaError error = felica_poller_write_blocks(
|
|
instance, 1, blocks, instance->data->data.fs.rc.data, &tx_resp);
|
|
if((error != FelicaErrorNone) || (tx_resp->SF1 != 0) || (tx_resp->SF2 != 0)) break;
|
|
|
|
blocks[0] = FELICA_BLOCK_INDEX_ID;
|
|
blocks[1] = FELICA_BLOCK_INDEX_WCNT;
|
|
blocks[2] = FELICA_BLOCK_INDEX_MAC_A;
|
|
FelicaPollerReadCommandResponse* rx_resp;
|
|
error = felica_poller_read_blocks(
|
|
instance, sizeof(blocks), blocks, FELICA_SERVICE_RO_ACCESS, &rx_resp);
|
|
if(error != FelicaErrorNone || rx_resp->SF1 != 0 || rx_resp->SF2 != 0) break;
|
|
|
|
if(felica_check_mac(
|
|
&instance->auth.des_context,
|
|
instance->auth.session_key.data,
|
|
instance->data->data.fs.rc.data,
|
|
blocks,
|
|
rx_resp->block_count,
|
|
rx_resp->data)) {
|
|
instance->auth.context.auth_status.internal = true;
|
|
instance->data->data.fs.wcnt.SF1 = 0;
|
|
instance->data->data.fs.wcnt.SF2 = 0;
|
|
memcpy(
|
|
instance->data->data.fs.wcnt.data,
|
|
rx_resp->data + FELICA_DATA_BLOCK_SIZE,
|
|
FELICA_DATA_BLOCK_SIZE);
|
|
instance->state = FelicaPollerStateAuthenticateExternal;
|
|
}
|
|
} while(false);
|
|
|
|
return NfcCommandContinue;
|
|
}
|
|
|
|
NfcCommand felica_poller_state_handler_auth_external(FelicaPoller* instance) {
|
|
FURI_LOG_D(TAG, "Auth External");
|
|
uint8_t blocks[2];
|
|
|
|
instance->data->data.fs.state.data[0] = 1;
|
|
FelicaAuthentication* auth = &instance->auth;
|
|
felica_calculate_mac_write(
|
|
&auth->des_context,
|
|
auth->session_key.data,
|
|
instance->data->data.fs.rc.data,
|
|
instance->data->data.fs.wcnt.data,
|
|
instance->data->data.fs.state.data,
|
|
instance->data->data.fs.mac_a.data);
|
|
|
|
memcpy(instance->data->data.fs.mac_a.data + 8, instance->data->data.fs.wcnt.data, 3); //-V1086
|
|
|
|
uint8_t tx_data[FELICA_DATA_BLOCK_SIZE * 2];
|
|
memcpy(tx_data, instance->data->data.fs.state.data, FELICA_DATA_BLOCK_SIZE);
|
|
memcpy(
|
|
tx_data + FELICA_DATA_BLOCK_SIZE,
|
|
instance->data->data.fs.mac_a.data,
|
|
FELICA_DATA_BLOCK_SIZE);
|
|
|
|
do {
|
|
blocks[0] = FELICA_BLOCK_INDEX_STATE;
|
|
blocks[1] = FELICA_BLOCK_INDEX_MAC_A;
|
|
FelicaPollerWriteCommandResponse* tx_resp;
|
|
FelicaError error = felica_poller_write_blocks(instance, 2, blocks, tx_data, &tx_resp);
|
|
if(error != FelicaErrorNone || tx_resp->SF1 != 0 || tx_resp->SF2 != 0) break;
|
|
|
|
FelicaPollerReadCommandResponse* rx_resp;
|
|
error = felica_poller_read_blocks(instance, 1, blocks, FELICA_SERVICE_RO_ACCESS, &rx_resp);
|
|
if(error != FelicaErrorNone || rx_resp->SF1 != 0 || rx_resp->SF2 != 0) break;
|
|
|
|
instance->data->data.fs.state.SF1 = 0;
|
|
instance->data->data.fs.state.SF2 = 0;
|
|
memcpy(instance->data->data.fs.state.data, rx_resp->data, FELICA_DATA_BLOCK_SIZE);
|
|
instance->auth.context.auth_status.external = instance->data->data.fs.state.data[0];
|
|
} while(false);
|
|
|
|
switch(instance->data->workflow_type) {
|
|
case FelicaStandard:
|
|
instance->state = FelicaPollerStateTraverseStandardSystem;
|
|
break;
|
|
case FelicaLite:
|
|
instance->state = FelicaPollerStateReadLiteBlocks;
|
|
break;
|
|
default:
|
|
// Unimplemented
|
|
instance->state = FelicaPollerStateReadSuccess;
|
|
break;
|
|
}
|
|
|
|
return NfcCommandContinue;
|
|
}
|
|
|
|
NfcCommand felica_poller_state_handler_traverse_standard_system(FelicaPoller* instance) {
|
|
FURI_LOG_D(TAG, "Traverse Standard System");
|
|
|
|
FelicaListServiceCommandResponse* response;
|
|
|
|
felica_service_array_t service_buffer;
|
|
felica_service_array_init(service_buffer);
|
|
felica_area_array_t area_buffer;
|
|
felica_area_array_init(area_buffer);
|
|
|
|
for(uint16_t cursor = 0; cursor < 0xFFFF; cursor++) {
|
|
FelicaError error = felica_poller_list_service_by_cursor(instance, cursor, &response);
|
|
if(error != FelicaErrorNone) {
|
|
FURI_LOG_E(TAG, "Error %d at cursor %04X", error, cursor);
|
|
break;
|
|
}
|
|
|
|
uint8_t len = response->header.length;
|
|
const uint8_t* list_service_payload = response->data;
|
|
uint16_t code_begin = (uint16_t)(list_service_payload[0] | (list_service_payload[1] << 8));
|
|
|
|
if(len != 0x0C && len != 0x0E) {
|
|
FURI_LOG_E(TAG, "Bad command resp length 0x%02X at cursor 0x%04X", len, cursor);
|
|
break;
|
|
}
|
|
|
|
if(code_begin == 0xFFFF) {
|
|
FURI_LOG_D(TAG, "Traverse complete");
|
|
break;
|
|
}
|
|
|
|
if(len == 0x0E) {
|
|
FelicaArea* area = felica_area_array_push_raw(area_buffer);
|
|
memset(area, 0, sizeof *area);
|
|
area->code = code_begin;
|
|
area->first_idx = (uint16_t)felica_service_array_size(service_buffer);
|
|
area->last_idx = 0;
|
|
} else {
|
|
FelicaService* service = felica_service_array_push_raw(service_buffer);
|
|
memset(service, 0, sizeof *service);
|
|
service->code = code_begin;
|
|
service->attr = (uint8_t)(code_begin & 0x3F);
|
|
|
|
FURI_LOG_D(TAG, "Service %04X", service->code);
|
|
|
|
if(felica_area_array_size(area_buffer)) {
|
|
FelicaArea* current_area = felica_area_array_back(area_buffer);
|
|
current_area->last_idx = (uint16_t)(felica_service_array_size(service_buffer) - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
const size_t service_num = felica_service_array_size(service_buffer);
|
|
const size_t area_num = felica_area_array_size(area_buffer);
|
|
|
|
FelicaSystem* system = simple_array_get(instance->data->systems, instance->systems_read);
|
|
if(service_num) {
|
|
simple_array_init(system->services, (uint32_t)service_num);
|
|
memcpy(
|
|
simple_array_get(system->services, 0),
|
|
service_buffer->ptr,
|
|
service_num * sizeof(FelicaService));
|
|
} else {
|
|
simple_array_reset(system->services);
|
|
}
|
|
|
|
if(area_num) {
|
|
simple_array_init(system->areas, (uint32_t)area_num);
|
|
memcpy(
|
|
simple_array_get(system->areas, 0), area_buffer->ptr, area_num * sizeof(FelicaArea));
|
|
} else {
|
|
simple_array_reset(system->areas);
|
|
}
|
|
|
|
FURI_LOG_I(
|
|
TAG,
|
|
"Services found: %lu, Areas found: %lu",
|
|
simple_array_get_count(system->services),
|
|
simple_array_get_count(system->areas));
|
|
|
|
felica_service_array_clear(service_buffer);
|
|
felica_area_array_clear(area_buffer);
|
|
|
|
instance->state = FelicaPollerStateReadStandardBlocks;
|
|
return NfcCommandContinue;
|
|
}
|
|
|
|
NfcCommand felica_poller_state_handler_read_standard_blocks(FelicaPoller* instance) {
|
|
FURI_LOG_D(TAG, "Read Standard Blocks");
|
|
|
|
FelicaSystem* system = simple_array_get(instance->data->systems, instance->systems_read);
|
|
const uint32_t service_count = simple_array_get_count(system->services);
|
|
|
|
felica_public_block_array_t public_block_buffer;
|
|
felica_public_block_array_init(public_block_buffer);
|
|
|
|
bool have_read_anything = false;
|
|
FelicaError error = FelicaErrorNone;
|
|
|
|
for(uint32_t i = 0; i < service_count; i++) {
|
|
const FelicaService* service = simple_array_get(system->services, i);
|
|
|
|
if((service->attr & FELICA_SERVICE_ATTRIBUTE_UNAUTH_READ) == 0) continue;
|
|
|
|
uint8_t block_count = 1;
|
|
uint8_t block_list[1] = {0};
|
|
FelicaPollerReadCommandResponse* response;
|
|
do {
|
|
error = felica_poller_read_blocks(
|
|
instance, block_count, block_list, service->code, &response);
|
|
|
|
if(error != FelicaErrorNone) {
|
|
break;
|
|
}
|
|
|
|
if(response->SF1 == 0 && response->SF2 == 0) {
|
|
FelicaPublicBlock* public_block =
|
|
felica_public_block_array_push_raw(public_block_buffer);
|
|
memset(public_block, 0, sizeof *public_block);
|
|
memcpy(public_block->block.data, response->data, FELICA_DATA_BLOCK_SIZE);
|
|
|
|
public_block->service_code = service->code;
|
|
public_block->block_idx = block_list[0];
|
|
|
|
have_read_anything = true;
|
|
block_list[0]++;
|
|
} else {
|
|
break; // No more blocks to read in this service, ok to continue for loop
|
|
}
|
|
} while(block_list[0] < FELICA_STANDARD_MAX_BLOCK_COUNT);
|
|
|
|
if(error != FelicaErrorNone) {
|
|
instance->felica_event.type = FelicaPollerEventTypeError;
|
|
instance->felica_event_data.error = error;
|
|
instance->state = FelicaPollerStateReadFailed;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(error == FelicaErrorNone) {
|
|
instance->systems_read++;
|
|
if(instance->systems_read == instance->systems_total) {
|
|
instance->state = FelicaPollerStateReadSuccess;
|
|
} else {
|
|
instance->state = FelicaPollerStateSelectSystemIndex;
|
|
}
|
|
}
|
|
|
|
if(have_read_anything) {
|
|
const size_t n = felica_public_block_array_size(public_block_buffer);
|
|
simple_array_init(system->public_blocks, (uint32_t)n);
|
|
memcpy(
|
|
simple_array_get(system->public_blocks, 0),
|
|
public_block_buffer->ptr,
|
|
n * sizeof(FelicaPublicBlock));
|
|
}
|
|
|
|
felica_public_block_array_clear(public_block_buffer);
|
|
|
|
return NfcCommandContinue;
|
|
}
|
|
|
|
NfcCommand felica_poller_state_handler_read_lite_blocks(FelicaPoller* instance) {
|
|
FURI_LOG_D(TAG, "Read Lite Blocks");
|
|
|
|
uint8_t block_count = 1;
|
|
uint8_t block_list[4] = {0, 0, 0, 0};
|
|
block_list[0] = instance->block_index;
|
|
|
|
instance->block_index++;
|
|
if(instance->block_index == FELICA_BLOCK_INDEX_REG + 1) {
|
|
instance->block_index = FELICA_BLOCK_INDEX_RC;
|
|
} else if(instance->block_index == FELICA_BLOCK_INDEX_MC + 1) {
|
|
instance->block_index = FELICA_BLOCK_INDEX_WCNT;
|
|
} else if(instance->block_index == FELICA_BLOCK_INDEX_STATE + 1) {
|
|
instance->block_index = FELICA_BLOCK_INDEX_CRC_CHECK;
|
|
}
|
|
|
|
FelicaPollerReadCommandResponse* response;
|
|
FelicaError error = felica_poller_read_blocks(
|
|
instance, block_count, block_list, FELICA_SERVICE_RO_ACCESS, &response);
|
|
if(error == FelicaErrorNone) {
|
|
block_count = (response->SF1 == 0) ? response->block_count : block_count;
|
|
uint8_t* data_ptr =
|
|
instance->data->data.dump + instance->data->blocks_total * sizeof(FelicaBlock);
|
|
|
|
*data_ptr++ = response->SF1;
|
|
*data_ptr++ = response->SF2;
|
|
|
|
if(response->SF1 == 0) {
|
|
uint8_t* response_data_ptr = response->data;
|
|
instance->data->blocks_read++;
|
|
memcpy(data_ptr, response_data_ptr, FELICA_DATA_BLOCK_SIZE);
|
|
} else {
|
|
memset(data_ptr, 0, FELICA_DATA_BLOCK_SIZE);
|
|
}
|
|
instance->data->blocks_total++;
|
|
|
|
if(instance->data->blocks_total == FELICA_BLOCKS_TOTAL_COUNT) {
|
|
instance->state = FelicaPollerStateReadSuccess;
|
|
}
|
|
} else {
|
|
instance->felica_event.type = FelicaPollerEventTypeError;
|
|
instance->felica_event_data.error = error;
|
|
instance->state = FelicaPollerStateReadFailed;
|
|
}
|
|
|
|
return NfcCommandContinue;
|
|
}
|
|
|
|
NfcCommand felica_poller_state_handler_read_success(FelicaPoller* instance) {
|
|
FURI_LOG_D(TAG, "Read Success");
|
|
|
|
if(!instance->auth.context.auth_status.internal ||
|
|
!instance->auth.context.auth_status.external) {
|
|
instance->data->blocks_read--;
|
|
instance->felica_event.type = FelicaPollerEventTypeIncomplete;
|
|
} else {
|
|
memcpy(
|
|
instance->data->data.fs.ck.data,
|
|
instance->auth.context.card_key.data,
|
|
FELICA_DATA_BLOCK_SIZE);
|
|
instance->felica_event.type = FelicaPollerEventTypeReady;
|
|
}
|
|
|
|
instance->data->idm.data[0] &= 0x0F;
|
|
|
|
instance->felica_event_data.error = FelicaErrorNone;
|
|
return instance->callback(instance->general_event, instance->context);
|
|
}
|
|
|
|
NfcCommand felica_poller_state_handler_read_failed(FelicaPoller* instance) {
|
|
FURI_LOG_D(TAG, "Read Fail");
|
|
instance->callback(instance->general_event, instance->context);
|
|
instance->data->idm.data[0] &= 0x0F;
|
|
|
|
return NfcCommandStop;
|
|
}
|
|
|
|
static const FelicaPollerReadHandler felica_poller_handler[FelicaPollerStateNum] = {
|
|
[FelicaPollerStateIdle] = felica_poller_state_handler_idle,
|
|
[FelicaPollerStateActivated] = felica_poller_state_handler_activate,
|
|
[FelicaPollerStateListSystem] = felica_poller_state_handler_list_system,
|
|
[FelicaPollerStateSelectSystemIndex] = felica_poller_state_handler_select_system_idx,
|
|
[FelicaPollerStateAuthenticateInternal] = felica_poller_state_handler_auth_internal,
|
|
[FelicaPollerStateAuthenticateExternal] = felica_poller_state_handler_auth_external,
|
|
[FelicaPollerStateTraverseStandardSystem] =
|
|
felica_poller_state_handler_traverse_standard_system,
|
|
[FelicaPollerStateReadStandardBlocks] = felica_poller_state_handler_read_standard_blocks,
|
|
[FelicaPollerStateReadLiteBlocks] = felica_poller_state_handler_read_lite_blocks,
|
|
[FelicaPollerStateReadSuccess] = felica_poller_state_handler_read_success,
|
|
[FelicaPollerStateReadFailed] = felica_poller_state_handler_read_failed,
|
|
};
|
|
|
|
static NfcCommand felica_poller_run(NfcGenericEvent event, void* context) {
|
|
furi_assert(context);
|
|
furi_assert(event.protocol == NfcProtocolInvalid);
|
|
furi_assert(event.event_data);
|
|
|
|
FelicaPoller* instance = context;
|
|
NfcEvent* nfc_event = event.event_data;
|
|
NfcCommand command = NfcCommandContinue;
|
|
|
|
if(nfc_event->type == NfcEventTypePollerReady) {
|
|
command = felica_poller_handler[instance->state](instance);
|
|
}
|
|
|
|
return command;
|
|
}
|
|
|
|
static bool felica_poller_detect(NfcGenericEvent event, void* context) {
|
|
furi_assert(context);
|
|
furi_assert(event.event_data);
|
|
furi_assert(event.instance);
|
|
furi_assert(event.protocol == NfcProtocolInvalid);
|
|
|
|
bool protocol_detected = false;
|
|
FelicaPoller* instance = context;
|
|
NfcEvent* nfc_event = event.event_data;
|
|
furi_assert(instance->state == FelicaPollerStateIdle);
|
|
|
|
if(nfc_event->type == NfcEventTypePollerReady) {
|
|
FelicaError error = felica_poller_activate(instance, instance->data);
|
|
protocol_detected = (error == FelicaErrorNone);
|
|
}
|
|
|
|
return protocol_detected;
|
|
}
|
|
|
|
const NfcPollerBase nfc_poller_felica = {
|
|
.alloc = (NfcPollerAlloc)felica_poller_alloc,
|
|
.free = (NfcPollerFree)felica_poller_free,
|
|
.set_callback = (NfcPollerSetCallback)felica_poller_set_callback,
|
|
.run = (NfcPollerRun)felica_poller_run,
|
|
.detect = (NfcPollerDetect)felica_poller_detect,
|
|
.get_data = (NfcPollerGetData)felica_poller_get_data,
|
|
};
|