1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-12 12:42:30 +04:00

ofw pr 4293 NFC FeliCa Improvement: Dump All Systems

by zinongli
This commit is contained in:
MX
2025-10-12 03:39:38 +03:00
parent fc34205f97
commit eed1d3367a
14 changed files with 569 additions and 325 deletions

View File

@@ -102,6 +102,7 @@ static void nfc_scene_read_success_on_enter_felica(NfcApp* instance) {
temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
nfc_render_felica_info(data, NfcProtocolFormatTypeShort, temp_str); nfc_render_felica_info(data, NfcProtocolFormatTypeShort, temp_str);
} else { } else {
if(data->workflow_type == FelicaLite) {
bool all_unlocked = data->blocks_read == data->blocks_total; bool all_unlocked = data->blocks_read == data->blocks_total;
furi_string_cat_printf( furi_string_cat_printf(
temp_str, temp_str,
@@ -116,6 +117,7 @@ static void nfc_scene_read_success_on_enter_felica(NfcApp* instance) {
} }
nfc_render_felica_blocks_count(data, temp_str, false); nfc_render_felica_blocks_count(data, temp_str, false);
} }
}
felica_auth_reset(instance->felica_auth); felica_auth_reset(instance->felica_auth);
widget_add_text_scroll_element( widget_add_text_scroll_element(
@@ -124,6 +126,15 @@ static void nfc_scene_read_success_on_enter_felica(NfcApp* instance) {
furi_string_free(temp_str); furi_string_free(temp_str);
} }
static bool nfc_scene_saved_menu_on_event_felica(NfcApp* instance, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom && event.event == SubmenuIndexCommonEdit) {
scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid);
return true;
}
return false;
}
static void nfc_scene_emulate_on_enter_felica(NfcApp* instance) { static void nfc_scene_emulate_on_enter_felica(NfcApp* instance) {
const FelicaData* data = nfc_device_get_data(instance->nfc_device, NfcProtocolFelica); const FelicaData* data = nfc_device_get_data(instance->nfc_device, NfcProtocolFelica);
instance->listener = nfc_listener_alloc(instance->nfc, NfcProtocolFelica, data); instance->listener = nfc_listener_alloc(instance->nfc, NfcProtocolFelica, data);
@@ -183,7 +194,7 @@ const NfcProtocolSupportBase nfc_protocol_support_felica = {
.scene_saved_menu = .scene_saved_menu =
{ {
.on_enter = nfc_protocol_support_common_on_enter_empty, .on_enter = nfc_protocol_support_common_on_enter_empty,
.on_event = nfc_protocol_support_common_on_event_empty, .on_event = nfc_scene_saved_menu_on_event_felica,
}, },
.scene_save_name = .scene_save_name =
{ {
@@ -195,11 +206,4 @@ const NfcProtocolSupportBase nfc_protocol_support_felica = {
.on_enter = nfc_scene_emulate_on_enter_felica, .on_enter = nfc_scene_emulate_on_enter_felica,
.on_event = nfc_protocol_support_common_on_event_empty, .on_event = nfc_protocol_support_common_on_event_empty,
}, },
.scene_write =
{
.on_enter = nfc_protocol_support_common_on_enter_empty,
.on_event = nfc_protocol_support_common_on_event_empty,
},
}; };
NFC_PROTOCOL_SUPPORT_PLUGIN(felica, NfcProtocolFelica);

View File

@@ -6,14 +6,10 @@ void nfc_render_felica_blocks_count(
bool render_auth_notification) { bool render_auth_notification) {
if(data->workflow_type == FelicaLite) { if(data->workflow_type == FelicaLite) {
furi_string_cat_printf(str, "Blocks: %u\n", data->blocks_total); furi_string_cat_printf(str, "Blocks: %u\n", data->blocks_total);
furi_string_cat_printf(str, "\nBlocks Read: %u/%u", data->blocks_read, data->blocks_total); furi_string_cat_printf(str, "\nBlocks Read: %u/%u", data->blocks_read, data->blocks_total);
if(render_auth_notification && data->blocks_read != data->blocks_total) { if(render_auth_notification && data->blocks_read != data->blocks_total) {
furi_string_cat_printf(str, "\nAuth-protected blocks!"); furi_string_cat_printf(str, "\nAuth-protected blocks!");
} }
} else if(data->workflow_type == FelicaStandard) {
furi_string_cat_printf(
str, "Public blocks Read: %lu", simple_array_get_count(data->public_blocks));
} }
} }
@@ -54,11 +50,7 @@ void nfc_render_felica_info(
} }
furi_string_cat_printf(str, "\n"); furi_string_cat_printf(str, "\n");
furi_string_cat_printf( furi_string_cat_printf(str, "Systems found: %lu \n", simple_array_get_count(data->systems));
str,
"Services found: %lu \nAreas found: %lu\n",
simple_array_get_count(data->services),
simple_array_get_count(data->areas));
nfc_render_felica_blocks_count(data, str, true); nfc_render_felica_blocks_count(data, str, true);
} }
@@ -136,9 +128,9 @@ void nfc_more_info_render_felica_lite_dump(const FelicaData* data, FuriString* s
nfc_render_felica_block(&data->data.fs.crc_check, str, "CRC_CHCK", 15, 17); nfc_render_felica_block(&data->data.fs.crc_check, str, "CRC_CHCK", 15, 17);
} }
void nfc_more_info_render_felica_dir(const FelicaData* data, FuriString* str) { void nfc_more_info_render_felica_dir(const FelicaSystem* system, FuriString* str) {
const size_t area_count = simple_array_get_count(data->areas); const size_t area_count = simple_array_get_count(system->areas);
const size_t service_count = simple_array_get_count(data->services); const size_t service_count = simple_array_get_count(system->services);
furi_string_cat_printf(str, "\e#Directory Tree:\n"); furi_string_cat_printf(str, "\e#Directory Tree:\n");
@@ -150,11 +142,12 @@ void nfc_more_info_render_felica_dir(const FelicaData* data, FuriString* str) {
furi_string_cat_printf( furi_string_cat_printf(
str, "::: ... are readable services\n||| ... are locked services\n"); str, "::: ... are readable services\n||| ... are locked services\n");
} }
felica_write_directory_tree(data, str); felica_write_directory_tree(system, str);
} }
void nfc_more_info_render_felica_blocks( void nfc_more_info_render_felica_blocks(
const FelicaData* data, const FelicaData* data,
const FelicaSystem* system,
FuriString* str, FuriString* str,
const uint16_t service_code_key) { const uint16_t service_code_key) {
furi_string_cat_printf(str, "\n"); furi_string_cat_printf(str, "\n");
@@ -190,9 +183,9 @@ void nfc_more_info_render_felica_blocks(
nfc_render_felica_block(&data->data.fs.crc_check, str, "CRC_CHCK", 15, 17); nfc_render_felica_block(&data->data.fs.crc_check, str, "CRC_CHCK", 15, 17);
} else if(data->workflow_type == FelicaStandard) { } else if(data->workflow_type == FelicaStandard) {
uint32_t public_blocks_count = simple_array_get_count(data->public_blocks); uint32_t public_blocks_count = simple_array_get_count(system->public_blocks);
for(size_t i = 0; i < public_blocks_count; i++) { for(size_t i = 0; i < public_blocks_count; i++) {
FelicaPublicBlock* public_block = simple_array_get(data->public_blocks, i); FelicaPublicBlock* public_block = simple_array_get(system->public_blocks, i);
if(public_block->service_code != service_code_key) { if(public_block->service_code != service_code_key) {
continue; // Skip blocks not matching the requested service code continue; // Skip blocks not matching the requested service code
} }

View File

@@ -21,9 +21,10 @@ void nfc_render_felica_idm(
NfcProtocolFormatType format_type, NfcProtocolFormatType format_type,
FuriString* str); FuriString* str);
void nfc_more_info_render_felica_dir(const FelicaData* data, FuriString* str); void nfc_more_info_render_felica_dir(const FelicaSystem* system, FuriString* str);
void nfc_more_info_render_felica_blocks( void nfc_more_info_render_felica_blocks(
const FelicaData* data, const FelicaData* data,
const FelicaSystem* system,
FuriString* str, FuriString* str,
const uint16_t service_code_key); const uint16_t service_code_key);

View File

@@ -70,5 +70,6 @@ ADD_SCENE(nfc, slix_unlock, SlixUnlock)
ADD_SCENE(nfc, slix_unlock_success, SlixUnlockSuccess) ADD_SCENE(nfc, slix_unlock_success, SlixUnlockSuccess)
ADD_SCENE(nfc, felica_more_info, FelicaMoreInfo) ADD_SCENE(nfc, felica_more_info, FelicaMoreInfo)
ADD_SCENE(nfc, felica_system, FelicaSystem)
ADD_SCENE(nfc, generate_info, GenerateInfo) ADD_SCENE(nfc, generate_info, GenerateInfo)

View File

@@ -9,7 +9,6 @@ enum {
}; };
enum SubmenuIndex { enum SubmenuIndex {
SubmenuIndexDirectory,
SubmenuIndexDynamic, // dynamic indices start here SubmenuIndexDynamic, // dynamic indices start here
}; };
@@ -21,33 +20,22 @@ void nfc_scene_felica_more_info_on_enter(void* context) {
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneFelicaMoreInfo); scene_manager_get_scene_state(nfc->scene_manager, NfcSceneFelicaMoreInfo);
const FelicaData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolFelica); const FelicaData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolFelica);
submenu_add_item(
submenu,
"Directory",
SubmenuIndexDirectory,
nfc_protocol_support_common_submenu_callback,
nfc);
FuriString* label = furi_string_alloc();
switch(data->workflow_type) { switch(data->workflow_type) {
case FelicaLite: case FelicaLite:
furi_string_printf(label, "All blocks"); widget_reset(nfc->widget);
submenu_add_item( FuriString* temp_str = furi_string_alloc();
submenu, nfc_more_info_render_felica_lite_dump(data, temp_str);
furi_string_get_cstr(label), widget_add_text_scroll_element(nfc->widget, 0, 0, 128, 64, furi_string_get_cstr(temp_str));
SubmenuIndexDynamic, furi_string_free(temp_str);
nfc_protocol_support_common_submenu_callback, view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
nfc); return;
break; break;
case FelicaStandard: case FelicaStandard:
for(uint32_t i = 0; i < simple_array_get_count(data->services); ++i) { FuriString* label = furi_string_alloc();
const FelicaService* service = simple_array_cget(data->services, i);
bool is_public = (service->attr & FELICA_SERVICE_ATTRIBUTE_UNAUTH_READ) == 1; for(uint32_t i = 0; i < simple_array_get_count(data->systems); ++i) {
if(!is_public) { const FelicaSystem* system = simple_array_cget(data->systems, i);
continue; furi_string_printf(label, "System %04X", system->system_code);
}
furi_string_printf(label, "Readable serv %04X", service->code);
submenu_add_item( submenu_add_item(
submenu, submenu,
furi_string_get_cstr(label), furi_string_get_cstr(label),
@@ -55,13 +43,12 @@ void nfc_scene_felica_more_info_on_enter(void* context) {
nfc_protocol_support_common_submenu_callback, nfc_protocol_support_common_submenu_callback,
nfc); nfc);
} }
furi_string_free(label);
break; break;
default: default:
break; break;
} }
furi_string_free(label);
if(state >= FelicaMoreInfoStateItem) { if(state >= FelicaMoreInfoStateItem) {
submenu_set_selected_item( submenu_set_selected_item(
nfc->submenu, state - FelicaMoreInfoStateItem + SubmenuIndexDynamic); nfc->submenu, state - FelicaMoreInfoStateItem + SubmenuIndexDynamic);
@@ -78,49 +65,16 @@ bool nfc_scene_felica_more_info_on_event(void* context, SceneManagerEvent event)
const uint32_t state = const uint32_t state =
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneFelicaMoreInfo); scene_manager_get_scene_state(nfc->scene_manager, NfcSceneFelicaMoreInfo);
const FelicaData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolFelica);
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexDirectory) { const uint32_t index = event.event - SubmenuIndexDynamic;
FuriString* temp_str = furi_string_alloc();
nfc_more_info_render_felica_dir(data, temp_str);
widget_add_text_scroll_element(
nfc->widget, 0, 0, 128, 64, furi_string_get_cstr(temp_str));
furi_string_free(temp_str);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
scene_manager_set_scene_state( scene_manager_set_scene_state(
nfc->scene_manager, nfc->scene_manager, NfcSceneFelicaMoreInfo, FelicaMoreInfoStateItem + index);
NfcSceneFelicaMoreInfo, scene_manager_set_scene_state(nfc->scene_manager, NfcSceneFelicaSystem, index << 4);
FelicaMoreInfoStateItem + SubmenuIndexDirectory); scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaSystem);
consumed = true; consumed = true;
} else {
const uint16_t service_ind = event.event - 1; // offset the three enums above
text_box_reset(nfc->text_box);
furi_string_reset(nfc->text_box_store);
switch(data->workflow_type) {
case FelicaLite:
nfc_more_info_render_felica_lite_dump(data, nfc->text_box_store);
break;
case FelicaStandard:
const FelicaService* service = simple_array_cget(data->services, service_ind);
furi_string_cat_printf(nfc->text_box_store, "Service 0x%04X\n", service->code);
nfc_more_info_render_felica_blocks(data, nfc->text_box_store, service->code);
break;
default:
furi_string_set_str(nfc->text_box_store, "IC type not implemented yet");
break;
}
text_box_set_font(nfc->text_box, TextBoxFontHex);
text_box_set_text(nfc->text_box, furi_string_get_cstr(nfc->text_box_store));
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneFelicaMoreInfo, FelicaMoreInfoStateItem + event.event);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) { } else if(event.type == SceneManagerEventTypeBack) {
if(state >= FelicaMoreInfoStateItem) { if(state >= FelicaMoreInfoStateItem) {
widget_reset(nfc->widget); widget_reset(nfc->widget);

View File

@@ -0,0 +1,114 @@
#include "../nfc_app_i.h"
#include "../helpers/protocol_support/nfc_protocol_support_gui_common.h"
#include "../helpers/protocol_support/felica/felica_render.h"
enum SubmenuIndex {
SubmenuIndexDirectory,
SubmenuIndexDynamic, // dynamic indices start here
};
static void nfc_scene_felica_system_submenu_callback(void* context, uint32_t index) {
NfcApp* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
}
void nfc_scene_felica_system_on_enter(void* context) {
NfcApp* nfc = context;
Submenu* submenu = nfc->submenu;
submenu_reset(nfc->submenu);
const uint32_t system_index =
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneFelicaSystem) >> 4;
const FelicaData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolFelica);
submenu_add_item(
submenu, "Directory", SubmenuIndexDirectory, nfc_scene_felica_system_submenu_callback, nfc);
FuriString* label = furi_string_alloc();
const FelicaSystem* system = simple_array_cget(data->systems, system_index);
for(uint32_t i = 0; i < simple_array_get_count(system->services); ++i) {
const FelicaService* service = simple_array_cget(system->services, i);
bool is_public = (service->attr & FELICA_SERVICE_ATTRIBUTE_UNAUTH_READ) == 1;
if(!is_public) {
continue;
}
furi_string_printf(label, "Readable serv %04X", service->code);
submenu_add_item(
submenu,
furi_string_get_cstr(label),
i + SubmenuIndexDynamic,
nfc_protocol_support_common_submenu_callback,
nfc);
}
furi_string_free(label);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
}
bool nfc_scene_felica_system_on_event(void* context, SceneManagerEvent event) {
NfcApp* nfc = context;
bool consumed = false;
const uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneFelicaSystem);
const FelicaData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolFelica);
const uint32_t system_index = state >> 4;
const FelicaSystem* system = simple_array_cget(data->systems, system_index);
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventViewExit) {
consumed = scene_manager_previous_scene(nfc->scene_manager);
} else {
if(event.event == SubmenuIndexDirectory) {
FuriString* temp_str = furi_string_alloc();
nfc_more_info_render_felica_dir(system, temp_str);
widget_add_text_scroll_element(
nfc->widget, 0, 0, 128, 64, furi_string_get_cstr(temp_str));
furi_string_free(temp_str);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
} else {
const uint32_t service_ind =
event.event - SubmenuIndexDynamic; // offset the three enums above
text_box_reset(nfc->text_box);
furi_string_reset(nfc->text_box_store);
const FelicaService* service = simple_array_cget(system->services, service_ind);
furi_string_cat_printf(nfc->text_box_store, "Service 0x%04X\n", service->code);
nfc_more_info_render_felica_blocks(
data, system, nfc->text_box_store, service->code);
text_box_set_font(nfc->text_box, TextBoxFontHex);
text_box_set_text(nfc->text_box, furi_string_get_cstr(nfc->text_box_store));
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneFelicaSystem, state | 1);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
if(state & 1) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneFelicaSystem, state & ~1);
consumed = true;
}
}
return consumed;
}
void nfc_scene_felica_system_on_exit(void* context) {
NfcApp* nfc = context;
// Clear views
widget_reset(nfc->widget);
text_box_reset(nfc->text_box);
furi_string_reset(nfc->text_box_store);
submenu_reset(nfc->submenu);
}

View File

@@ -42,26 +42,16 @@ FelicaData* felica_alloc(void) {
FelicaData* data = malloc(sizeof(FelicaData)); FelicaData* data = malloc(sizeof(FelicaData));
furi_check(data); furi_check(data);
data->services = simple_array_alloc(&felica_service_array_cfg); data->systems = simple_array_alloc(&felica_system_array_cfg);
data->areas = simple_array_alloc(&felica_area_array_cfg); furi_check(data->systems);
data->public_blocks = simple_array_alloc(&felica_public_block_array_cfg);
furi_check(data->services);
furi_check(data->areas);
furi_check(data->public_blocks);
return data; return data;
} }
void felica_free(FelicaData* data) { void felica_free(FelicaData* data) {
furi_check(data); furi_check(data);
furi_check(data->services); furi_check(data->systems);
simple_array_free(data->services); simple_array_free(data->systems);
furi_check(data->areas);
simple_array_free(data->areas);
furi_check(data->public_blocks);
simple_array_free(data->public_blocks);
free(data); free(data);
} }
@@ -69,16 +59,8 @@ void felica_free(FelicaData* data) {
void felica_reset(FelicaData* data) { void felica_reset(FelicaData* data) {
furi_check(data); furi_check(data);
if(data->services) { if(data->systems) {
simple_array_reset(data->services); simple_array_reset(data->systems);
}
if(data->areas) {
simple_array_reset(data->areas);
}
if(data->public_blocks) {
simple_array_reset(data->public_blocks);
} }
data->blocks_read = 0; data->blocks_read = 0;
@@ -102,9 +84,7 @@ void felica_copy(FelicaData* data, const FelicaData* other) {
data->data = other->data; data->data = other->data;
data->workflow_type = other->workflow_type; data->workflow_type = other->workflow_type;
simple_array_copy(data->services, other->services); simple_array_copy(data->systems, other->systems);
simple_array_copy(data->areas, other->areas);
simple_array_copy(data->public_blocks, other->public_blocks);
} }
bool felica_verify(FelicaData* data, const FuriString* device_type) { bool felica_verify(FelicaData* data, const FuriString* device_type) {
@@ -175,11 +155,33 @@ bool felica_load(FelicaData* data, FlipperFormat* ff, uint32_t version) {
} while(false); } while(false);
break; break;
case FelicaStandard: case FelicaStandard:
uint32_t systems_total = 0;
if(!flipper_format_read_uint32(ff, "System found", &systems_total, 1)) break;
simple_array_init(data->systems, systems_total);
for(uint8_t sys_idx = 0; sys_idx < systems_total; sys_idx++) {
FelicaSystem* system = simple_array_get(data->systems, sys_idx);
uint16_t system_code = 0;
furi_string_reset(str_key_buffer);
furi_string_reset(str_data_buffer);
furi_string_printf(str_key_buffer, "System %02X", sys_idx);
if(!flipper_format_read_string(
ff, furi_string_get_cstr(str_key_buffer), str_data_buffer))
break;
if(!sscanf(furi_string_get_cstr(str_data_buffer), "%04hX", &system_code)) {
break;
}
system->system_code = system_code;
system->system_code_idx = sys_idx;
// Areas // Areas
do { do {
uint32_t area_count = 0; uint32_t area_count = 0;
if(!flipper_format_read_uint32(ff, "Area found", &area_count, 1)) break; if(!flipper_format_read_uint32(ff, "Area found", &area_count, 1)) break;
simple_array_init(data->areas, area_count); simple_array_init(system->areas, area_count);
furi_string_reset(str_key_buffer); furi_string_reset(str_key_buffer);
furi_string_reset(str_data_buffer); furi_string_reset(str_data_buffer);
@@ -189,7 +191,7 @@ bool felica_load(FelicaData* data, FlipperFormat* ff, uint32_t version) {
ff, furi_string_get_cstr(str_key_buffer), str_data_buffer)) { ff, furi_string_get_cstr(str_key_buffer), str_data_buffer)) {
break; break;
} }
FelicaArea* area = simple_array_get(data->areas, i); FelicaArea* area = simple_array_get(system->areas, i);
if(sscanf( if(sscanf(
furi_string_get_cstr(str_data_buffer), furi_string_get_cstr(str_data_buffer),
"| Code %04hX | Services #%03hX-#%03hX |", "| Code %04hX | Services #%03hX-#%03hX |",
@@ -205,7 +207,7 @@ bool felica_load(FelicaData* data, FlipperFormat* ff, uint32_t version) {
do { do {
uint32_t service_count = 0; uint32_t service_count = 0;
if(!flipper_format_read_uint32(ff, "Service found", &service_count, 1)) break; if(!flipper_format_read_uint32(ff, "Service found", &service_count, 1)) break;
simple_array_init(data->services, service_count); simple_array_init(system->services, service_count);
furi_string_reset(str_key_buffer); furi_string_reset(str_key_buffer);
furi_string_reset(str_data_buffer); furi_string_reset(str_data_buffer);
@@ -215,11 +217,13 @@ bool felica_load(FelicaData* data, FlipperFormat* ff, uint32_t version) {
ff, furi_string_get_cstr(str_key_buffer), str_data_buffer)) { ff, furi_string_get_cstr(str_key_buffer), str_data_buffer)) {
break; break;
} }
FelicaService* service = simple_array_get(data->services, i); FelicaService* service = simple_array_get(system->services, i);
// all unread in the beginning. reserved for future block load // all unread in the beginning. reserved for future block load
if(!sscanf( if(!sscanf(
furi_string_get_cstr(str_data_buffer), "| Code %04hX |", &service->code)) { furi_string_get_cstr(str_data_buffer),
"| Code %04hX |",
&service->code)) {
break; break;
} }
service->attr = service->code & 0x3F; service->attr = service->code & 0x3F;
@@ -233,7 +237,7 @@ bool felica_load(FelicaData* data, FlipperFormat* ff, uint32_t version) {
uint32_t public_block_count = 0; uint32_t public_block_count = 0;
if(!flipper_format_read_uint32(ff, "Public blocks read", &public_block_count, 1)) if(!flipper_format_read_uint32(ff, "Public blocks read", &public_block_count, 1))
break; break;
simple_array_init(data->public_blocks, public_block_count); simple_array_init(system->public_blocks, public_block_count);
for(uint16_t i = 0; i < public_block_count; i++) { for(uint16_t i = 0; i < public_block_count; i++) {
furi_string_printf(str_key_buffer, "Block %04X", i); furi_string_printf(str_key_buffer, "Block %04X", i);
if(!flipper_format_read_string( if(!flipper_format_read_string(
@@ -241,7 +245,7 @@ bool felica_load(FelicaData* data, FlipperFormat* ff, uint32_t version) {
break; break;
} }
FelicaPublicBlock* public_block = simple_array_get(data->public_blocks, i); FelicaPublicBlock* public_block = simple_array_get(system->public_blocks, i);
if(sscanf( if(sscanf(
furi_string_get_cstr(str_data_buffer), furi_string_get_cstr(str_data_buffer),
"| Service code %04hX | Block index %02hhX |", "| Service code %04hX | Block index %02hhX |",
@@ -264,10 +268,12 @@ bool felica_load(FelicaData* data, FlipperFormat* ff, uint32_t version) {
furi_string_reset(str_data_buffer); furi_string_reset(str_data_buffer);
for(size_t j = 0; j < FELICA_DATA_BLOCK_SIZE; j++) { for(size_t j = 0; j < FELICA_DATA_BLOCK_SIZE; j++) {
furi_string_cat_printf(str_data_buffer, "%02X ", public_block->block.data[j]); furi_string_cat_printf(
str_data_buffer, "%02X ", public_block->block.data[j]);
} }
} }
} while(false); } while(false);
}
break; break;
default: default:
break; break;
@@ -334,10 +340,23 @@ bool felica_save(const FelicaData* data, FlipperFormat* ff) {
case FelicaStandard: case FelicaStandard:
if(!flipper_format_write_comment_cstr(ff, "Felica Standard specific data")) break; if(!flipper_format_write_comment_cstr(ff, "Felica Standard specific data")) break;
uint32_t systems_count = simple_array_get_count(data->systems);
if(!flipper_format_write_uint32(ff, "System found", &systems_count, 1)) break;
for(uint32_t sys_idx = 0; sys_idx < systems_count; sys_idx++) {
FelicaSystem* system = simple_array_get(data->systems, sys_idx);
furi_string_reset(str_data_buffer);
furi_string_reset(str_key_buffer);
furi_string_printf(str_key_buffer, "\n\nSystem %02X", (uint8_t)sys_idx);
furi_string_printf(str_data_buffer, "%04X", system->system_code);
if(!flipper_format_write_string(
ff, furi_string_get_cstr(str_key_buffer), str_data_buffer))
break;
if(!flipper_format_write_empty_line(ff)) break;
do { do {
uint32_t area_count = simple_array_get_count(data->areas); uint32_t area_count = simple_array_get_count(system->areas);
uint32_t service_count = simple_array_get_count(data->services); uint32_t service_count = simple_array_get_count(system->services);
// Note: The theoretical max area/service count is 2^10 // Note: The theoretical max area/service count is 2^10
// So uint16_t is already enough for practical usage // So uint16_t is already enough for practical usage
// The following key index print will use %03X because 12 bits are enough to cover 0-1023 // The following key index print will use %03X because 12 bits are enough to cover 0-1023
@@ -349,7 +368,7 @@ bool felica_save(const FelicaData* data, FlipperFormat* ff) {
furi_string_reset(str_data_buffer); furi_string_reset(str_data_buffer);
furi_string_reset(str_key_buffer); furi_string_reset(str_key_buffer);
for(uint16_t i = 0; i < area_count; i++) { for(uint16_t i = 0; i < area_count; i++) {
FelicaArea* area = simple_array_get(data->areas, i); FelicaArea* area = simple_array_get(system->areas, i);
furi_string_printf(str_key_buffer, "Area %03X", i); furi_string_printf(str_key_buffer, "Area %03X", i);
furi_string_printf( furi_string_printf(
str_data_buffer, str_data_buffer,
@@ -370,10 +389,13 @@ bool felica_save(const FelicaData* data, FlipperFormat* ff) {
furi_string_reset(str_data_buffer); furi_string_reset(str_data_buffer);
furi_string_reset(str_key_buffer); furi_string_reset(str_key_buffer);
for(uint16_t i = 0; i < service_count; i++) { for(uint16_t i = 0; i < service_count; i++) {
FelicaService* service = simple_array_get(data->services, i); FelicaService* service = simple_array_get(system->services, i);
furi_string_printf(str_key_buffer, "Service %03X", i); furi_string_printf(str_key_buffer, "Service %03X", i);
furi_string_printf( furi_string_printf(
str_data_buffer, "| Code %04X | Attrib. %02X ", service->code, service->attr); str_data_buffer,
"| Code %04X | Attrib. %02X ",
service->code,
service->attr);
felica_service_get_attribute_string(service, str_data_buffer); felica_service_get_attribute_string(service, str_data_buffer);
if(!flipper_format_write_string( if(!flipper_format_write_string(
ff, furi_string_get_cstr(str_key_buffer), str_data_buffer)) ff, furi_string_get_cstr(str_key_buffer), str_data_buffer))
@@ -385,8 +407,9 @@ bool felica_save(const FelicaData* data, FlipperFormat* ff) {
furi_string_reset(str_data_buffer); furi_string_reset(str_data_buffer);
furi_string_reset(str_key_buffer); furi_string_reset(str_key_buffer);
furi_string_printf( furi_string_printf(
str_data_buffer, "\n::: ... are public services\n||| ... are private services"); str_data_buffer,
felica_write_directory_tree(data, str_data_buffer); "\n::: ... are public services\n||| ... are private services");
felica_write_directory_tree(system, str_data_buffer);
furi_string_replace_all(str_data_buffer, ":", "+"); furi_string_replace_all(str_data_buffer, ":", "+");
// We use a clearer marker in saved text files // We use a clearer marker in saved text files
if(!flipper_format_write_string(ff, "Directory Tree", str_data_buffer)) break; if(!flipper_format_write_string(ff, "Directory Tree", str_data_buffer)) break;
@@ -394,13 +417,13 @@ bool felica_save(const FelicaData* data, FlipperFormat* ff) {
// Public blocks // Public blocks
do { do {
uint32_t public_block_count = simple_array_get_count(data->public_blocks); uint32_t public_block_count = simple_array_get_count(system->public_blocks);
if(!flipper_format_write_uint32(ff, "Public blocks read", &public_block_count, 1)) if(!flipper_format_write_uint32(ff, "Public blocks read", &public_block_count, 1))
break; break;
furi_string_reset(str_data_buffer); furi_string_reset(str_data_buffer);
furi_string_reset(str_key_buffer); furi_string_reset(str_key_buffer);
for(uint16_t i = 0; i < public_block_count; i++) { for(uint16_t i = 0; i < public_block_count; i++) {
FelicaPublicBlock* public_block = simple_array_get(data->public_blocks, i); FelicaPublicBlock* public_block = simple_array_get(system->public_blocks, i);
furi_string_printf(str_key_buffer, "Block %04X", i); furi_string_printf(str_key_buffer, "Block %04X", i);
furi_string_printf( furi_string_printf(
str_data_buffer, str_data_buffer,
@@ -408,7 +431,8 @@ bool felica_save(const FelicaData* data, FlipperFormat* ff) {
public_block->service_code, public_block->service_code,
public_block->block_idx); public_block->block_idx);
for(uint8_t j = 0; j < FELICA_DATA_BLOCK_SIZE; j++) { for(uint8_t j = 0; j < FELICA_DATA_BLOCK_SIZE; j++) {
furi_string_cat_printf(str_data_buffer, "%02X ", public_block->block.data[j]); furi_string_cat_printf(
str_data_buffer, "%02X ", public_block->block.data[j]);
} }
furi_string_cat_printf(str_data_buffer, "|"); furi_string_cat_printf(str_data_buffer, "|");
if(!flipper_format_write_string( if(!flipper_format_write_string(
@@ -416,6 +440,7 @@ bool felica_save(const FelicaData* data, FlipperFormat* ff) {
break; break;
} }
} while(false); } while(false);
}
break; break;
default: default:
break; break;
@@ -436,9 +461,7 @@ bool felica_is_equal(const FelicaData* data, const FelicaData* other) {
memcmp(data->pmm.data, other->pmm.data, sizeof(FelicaPMm)) == 0 && memcmp(data->pmm.data, other->pmm.data, sizeof(FelicaPMm)) == 0 &&
data->blocks_total == other->blocks_total && data->blocks_read == other->blocks_read && data->blocks_total == other->blocks_total && data->blocks_read == other->blocks_read &&
memcmp(&data->data, &other->data, sizeof(data->data)) == 0 && memcmp(&data->data, &other->data, sizeof(data->data)) == 0 &&
simple_array_is_equal(data->services, other->services) && simple_array_is_equal(data->systems, other->systems);
simple_array_is_equal(data->areas, other->areas) &&
simple_array_is_equal(data->public_blocks, other->public_blocks);
} }
const char* felica_get_device_name(const FelicaData* data, NfcDeviceNameType name_type) { const char* felica_get_device_name(const FelicaData* data, NfcDeviceNameType name_type) {
@@ -640,8 +663,8 @@ void felica_calculate_mac_write(
felica_calculate_mac(ctx, session_swapped, rc, first_block, data, FELICA_DATA_BLOCK_SIZE, mac); felica_calculate_mac(ctx, session_swapped, rc, first_block, data, FELICA_DATA_BLOCK_SIZE, mac);
} }
void felica_write_directory_tree(const FelicaData* data, FuriString* str) { void felica_write_directory_tree(const FelicaSystem* system, FuriString* str) {
furi_check(data); furi_check(system);
furi_check(str); furi_check(str);
furi_string_cat_str(str, "\n"); furi_string_cat_str(str, "\n");
@@ -650,12 +673,12 @@ void felica_write_directory_tree(const FelicaData* data, FuriString* str) {
uint8_t depth = 0; uint8_t depth = 0;
size_t area_iter = 0; size_t area_iter = 0;
const size_t area_count = simple_array_get_count(data->areas); const size_t area_count = simple_array_get_count(system->areas);
const size_t service_count = simple_array_get_count(data->services); const size_t service_count = simple_array_get_count(system->services);
for(size_t svc_idx = 0; svc_idx < service_count; ++svc_idx) { for(size_t svc_idx = 0; svc_idx < service_count; ++svc_idx) {
while(area_iter < area_count) { while(area_iter < area_count) {
const FelicaArea* next_area = simple_array_get(data->areas, area_iter); const FelicaArea* next_area = simple_array_get(system->areas, area_iter);
if(next_area->first_idx != svc_idx) break; if(next_area->first_idx != svc_idx) break;
for(uint8_t i = 0; i < depth - 1; ++i) for(uint8_t i = 0; i < depth - 1; ++i)
@@ -667,7 +690,7 @@ void felica_write_directory_tree(const FelicaData* data, FuriString* str) {
area_iter++; area_iter++;
} }
const FelicaService* service = simple_array_get(data->services, svc_idx); const FelicaService* service = simple_array_get(system->services, svc_idx);
bool is_public = (service->attr & FELICA_SERVICE_ATTRIBUTE_UNAUTH_READ) != 0; bool is_public = (service->attr & FELICA_SERVICE_ATTRIBUTE_UNAUTH_READ) != 0;
for(uint8_t i = 0; i < depth - 1; ++i) for(uint8_t i = 0; i < depth - 1; ++i)

View File

@@ -52,6 +52,8 @@ extern "C" {
#define FELICA_CMD_LIST_SERVICE_CODE 0x0A #define FELICA_CMD_LIST_SERVICE_CODE 0x0A
#define FELICA_CMD_LIST_SERVICE_CODE_RESP 0x0B #define FELICA_CMD_LIST_SERVICE_CODE_RESP 0x0B
#define FELICA_CMD_REQUEST_SYSTEM_CODE 0x0C
#define FELICA_CMD_REQUEST_SYSTEM_CODE_RESP 0x0D
#define FELICA_SERVICE_ATTRIBUTE_UNAUTH_READ (0b000001) #define FELICA_SERVICE_ATTRIBUTE_UNAUTH_READ (0b000001)
#define FELICA_SERVICE_ATTRIBUTE_READ_ONLY (0b000010) #define FELICA_SERVICE_ATTRIBUTE_READ_ONLY (0b000010)
@@ -182,6 +184,14 @@ typedef struct {
uint8_t block_idx; uint8_t block_idx;
} FelicaPublicBlock; } FelicaPublicBlock;
typedef struct {
uint8_t system_code_idx;
uint16_t system_code;
SimpleArray* services;
SimpleArray* areas;
SimpleArray* public_blocks;
} FelicaSystem;
/** @brief Structure used to store Felica data and additional values about reading */ /** @brief Structure used to store Felica data and additional values about reading */
typedef struct { typedef struct {
FelicaIDm idm; FelicaIDm idm;
@@ -190,9 +200,8 @@ typedef struct {
uint8_t blocks_read; uint8_t blocks_read;
FelicaFSUnion data; FelicaFSUnion data;
SimpleArray* services; SimpleArray* systems;
SimpleArray* areas;
SimpleArray* public_blocks;
FelicaWorkflowType workflow_type; FelicaWorkflowType workflow_type;
} FelicaData; } FelicaData;
@@ -248,6 +257,12 @@ typedef struct {
uint8_t data[]; uint8_t data[];
} FelicaListServiceCommandResponse; } FelicaListServiceCommandResponse;
typedef struct {
FelicaCommandHeaderRaw header;
uint8_t system_count;
uint8_t system_code[];
} FelicaListSystemCodeCommandResponse;
typedef FelicaCommandResponseHeader FelicaListenerWriteCommandResponse; typedef FelicaCommandResponseHeader FelicaListenerWriteCommandResponse;
typedef FelicaCommandResponseHeader FelicaPollerWriteCommandResponse; typedef FelicaCommandResponseHeader FelicaPollerWriteCommandResponse;
@@ -309,7 +324,7 @@ void felica_calculate_mac_write(
const uint8_t* data, const uint8_t* data,
uint8_t* mac); uint8_t* mac);
void felica_write_directory_tree(const FelicaData* data, FuriString* str); void felica_write_directory_tree(const FelicaSystem* system, FuriString* str);
void felica_get_workflow_type(FelicaData* data); void felica_get_workflow_type(FelicaData* data);

View File

@@ -1,5 +1,36 @@
#include "felica_i.h" #include "felica_i.h"
void felica_system_init(FelicaSystem* system) {
system->system_code = 0;
system->system_code_idx = 0;
system->services = simple_array_alloc(&felica_service_array_cfg);
system->areas = simple_array_alloc(&felica_area_array_cfg);
system->public_blocks = simple_array_alloc(&felica_public_block_array_cfg);
}
void felica_system_reset(FelicaSystem* system) {
furi_check(system);
system->system_code = 0;
system->system_code_idx = 0;
furi_check(system->services);
furi_check(system->areas);
furi_check(system->public_blocks);
simple_array_free(system->services);
simple_array_free(system->areas);
simple_array_free(system->public_blocks);
memset(system, 0, sizeof(FelicaSystem));
}
void felica_system_copy(FelicaSystem* system, const FelicaSystem* other) {
furi_check(system);
furi_check(other);
system->system_code = other->system_code;
system->system_code_idx = other->system_code_idx;
simple_array_copy(system->services, other->services);
simple_array_copy(system->areas, other->areas);
simple_array_copy(system->public_blocks, other->public_blocks);
}
const SimpleArrayConfig felica_service_array_cfg = { const SimpleArrayConfig felica_service_array_cfg = {
.init = NULL, .init = NULL,
.copy = NULL, .copy = NULL,
@@ -20,3 +51,10 @@ const SimpleArrayConfig felica_public_block_array_cfg = {
.reset = NULL, .reset = NULL,
.type_size = sizeof(FelicaPublicBlock), .type_size = sizeof(FelicaPublicBlock),
}; };
const SimpleArrayConfig felica_system_array_cfg = {
.init = (SimpleArrayInit)felica_system_init,
.copy = (SimpleArrayCopy)felica_system_copy,
.reset = (SimpleArrayReset)felica_system_reset,
.type_size = sizeof(FelicaSystem),
};

View File

@@ -8,3 +8,8 @@
extern const SimpleArrayConfig felica_service_array_cfg; extern const SimpleArrayConfig felica_service_array_cfg;
extern const SimpleArrayConfig felica_area_array_cfg; extern const SimpleArrayConfig felica_area_array_cfg;
extern const SimpleArrayConfig felica_public_block_array_cfg; extern const SimpleArrayConfig felica_public_block_array_cfg;
extern const SimpleArrayConfig felica_system_array_cfg;
void felica_system_init(FelicaSystem* system);
void felica_system_reset(FelicaSystem* system);
void felica_system_copy(FelicaSystem* system, const FelicaSystem* other);

View File

@@ -12,6 +12,7 @@
ARRAY_DEF(felica_service_array, FelicaService, M_POD_OPLIST); // -V658 ARRAY_DEF(felica_service_array, FelicaService, M_POD_OPLIST); // -V658
ARRAY_DEF(felica_area_array, FelicaArea, 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_public_block_array, FelicaPublicBlock, M_POD_OPLIST); // -V658
ARRAY_DEF(felica_system_array, FelicaSystem, M_POD_OPLIST); // -V658
typedef NfcCommand (*FelicaPollerReadHandler)(FelicaPoller* instance); typedef NfcCommand (*FelicaPollerReadHandler)(FelicaPoller* instance);
@@ -43,6 +44,9 @@ static FelicaPoller* felica_poller_alloc(Nfc* nfc) {
instance->general_event.event_data = &instance->felica_event; instance->general_event.event_data = &instance->felica_event;
instance->general_event.instance = instance; instance->general_event.instance = instance;
instance->systems_read = 0;
instance->systems_total = 0;
return instance; return instance;
} }
@@ -94,7 +98,7 @@ NfcCommand felica_poller_state_handler_activate(FelicaPoller* instance) {
switch(instance->data->workflow_type) { switch(instance->data->workflow_type) {
case FelicaStandard: case FelicaStandard:
instance->state = FelicaPollerStateTraverseStandardSystem; instance->state = FelicaPollerStateListSystem;
break; break;
case FelicaLite: case FelicaLite:
instance->state = FelicaPollerStateReadLiteBlocks; instance->state = FelicaPollerStateReadLiteBlocks;
@@ -117,6 +121,44 @@ NfcCommand felica_poller_state_handler_activate(FelicaPoller* instance) {
return command; 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) { NfcCommand felica_poller_state_handler_auth_internal(FelicaPoller* instance) {
FURI_LOG_D(TAG, "Auth Internal"); FURI_LOG_D(TAG, "Auth Internal");
@@ -274,6 +316,8 @@ NfcCommand felica_poller_state_handler_traverse_standard_system(FelicaPoller* in
service->code = code_begin; service->code = code_begin;
service->attr = (uint8_t)(code_begin & 0x3F); service->attr = (uint8_t)(code_begin & 0x3F);
FURI_LOG_D(TAG, "Service %04X", service->code);
if(felica_area_array_size(area_buffer)) { if(felica_area_array_size(area_buffer)) {
FelicaArea* current_area = felica_area_array_back(area_buffer); FelicaArea* current_area = felica_area_array_back(area_buffer);
current_area->last_idx = (uint16_t)(felica_service_array_size(service_buffer) - 1); current_area->last_idx = (uint16_t)(felica_service_array_size(service_buffer) - 1);
@@ -284,31 +328,30 @@ NfcCommand felica_poller_state_handler_traverse_standard_system(FelicaPoller* in
const size_t service_num = felica_service_array_size(service_buffer); const size_t service_num = felica_service_array_size(service_buffer);
const size_t area_num = felica_area_array_size(area_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) { if(service_num) {
simple_array_init(instance->data->services, (uint32_t)service_num); simple_array_init(system->services, (uint32_t)service_num);
memcpy( memcpy(
simple_array_get(instance->data->services, 0), simple_array_get(system->services, 0),
service_buffer->ptr, service_buffer->ptr,
service_num * sizeof(FelicaService)); service_num * sizeof(FelicaService));
} else { } else {
simple_array_reset(instance->data->services); simple_array_reset(system->services);
} }
if(area_num) { if(area_num) {
simple_array_init(instance->data->areas, (uint32_t)area_num); simple_array_init(system->areas, (uint32_t)area_num);
memcpy( memcpy(
simple_array_get(instance->data->areas, 0), simple_array_get(system->areas, 0), area_buffer->ptr, area_num * sizeof(FelicaArea));
area_buffer->ptr,
area_num * sizeof(FelicaArea));
} else { } else {
simple_array_reset(instance->data->areas); simple_array_reset(system->areas);
} }
FURI_LOG_I( FURI_LOG_I(
TAG, TAG,
"Services found: %lu, Areas found: %lu", "Services found: %lu, Areas found: %lu",
simple_array_get_count(instance->data->services), simple_array_get_count(system->services),
simple_array_get_count(instance->data->areas)); simple_array_get_count(system->areas));
felica_service_array_clear(service_buffer); felica_service_array_clear(service_buffer);
felica_area_array_clear(area_buffer); felica_area_array_clear(area_buffer);
@@ -320,22 +363,22 @@ NfcCommand felica_poller_state_handler_traverse_standard_system(FelicaPoller* in
NfcCommand felica_poller_state_handler_read_standard_blocks(FelicaPoller* instance) { NfcCommand felica_poller_state_handler_read_standard_blocks(FelicaPoller* instance) {
FURI_LOG_D(TAG, "Read Standard Blocks"); FURI_LOG_D(TAG, "Read Standard Blocks");
const uint32_t service_count = simple_array_get_count(instance->data->services); 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_t public_block_buffer;
felica_public_block_array_init(public_block_buffer); felica_public_block_array_init(public_block_buffer);
instance->state = FelicaPollerStateReadSuccess;
bool have_read_anything = false; bool have_read_anything = false;
FelicaError error = FelicaErrorNone;
for(uint32_t i = 0; i < service_count; i++) { for(uint32_t i = 0; i < service_count; i++) {
const FelicaService* service = simple_array_get(instance->data->services, i); const FelicaService* service = simple_array_get(system->services, i);
if((service->attr & FELICA_SERVICE_ATTRIBUTE_UNAUTH_READ) == 0) continue; if((service->attr & FELICA_SERVICE_ATTRIBUTE_UNAUTH_READ) == 0) continue;
uint8_t block_count = 1; uint8_t block_count = 1;
uint8_t block_list[1] = {0}; uint8_t block_list[1] = {0};
FelicaError error = FelicaErrorNone;
FelicaPollerReadCommandResponse* response; FelicaPollerReadCommandResponse* response;
do { do {
error = felica_poller_read_blocks( error = felica_poller_read_blocks(
@@ -369,11 +412,20 @@ NfcCommand felica_poller_state_handler_read_standard_blocks(FelicaPoller* instan
} }
} }
if(error == FelicaErrorNone) {
instance->systems_read++;
if(instance->systems_read == instance->systems_total) {
instance->state = FelicaPollerStateReadSuccess;
} else {
instance->state = FelicaPollerStateSelectSystemIndex;
}
}
if(have_read_anything) { if(have_read_anything) {
const size_t n = felica_public_block_array_size(public_block_buffer); const size_t n = felica_public_block_array_size(public_block_buffer);
simple_array_init(instance->data->public_blocks, (uint32_t)n); simple_array_init(system->public_blocks, (uint32_t)n);
memcpy( memcpy(
simple_array_get(instance->data->public_blocks, 0), simple_array_get(system->public_blocks, 0),
public_block_buffer->ptr, public_block_buffer->ptr,
n * sizeof(FelicaPublicBlock)); n * sizeof(FelicaPublicBlock));
} }
@@ -446,6 +498,8 @@ NfcCommand felica_poller_state_handler_read_success(FelicaPoller* instance) {
instance->felica_event.type = FelicaPollerEventTypeReady; instance->felica_event.type = FelicaPollerEventTypeReady;
} }
instance->data->idm.data[0] &= 0x0F;
instance->felica_event_data.error = FelicaErrorNone; instance->felica_event_data.error = FelicaErrorNone;
return instance->callback(instance->general_event, instance->context); return instance->callback(instance->general_event, instance->context);
} }
@@ -453,6 +507,7 @@ NfcCommand felica_poller_state_handler_read_success(FelicaPoller* instance) {
NfcCommand felica_poller_state_handler_read_failed(FelicaPoller* instance) { NfcCommand felica_poller_state_handler_read_failed(FelicaPoller* instance) {
FURI_LOG_D(TAG, "Read Fail"); FURI_LOG_D(TAG, "Read Fail");
instance->callback(instance->general_event, instance->context); instance->callback(instance->general_event, instance->context);
instance->data->idm.data[0] &= 0x0F;
return NfcCommandStop; return NfcCommandStop;
} }
@@ -460,6 +515,8 @@ NfcCommand felica_poller_state_handler_read_failed(FelicaPoller* instance) {
static const FelicaPollerReadHandler felica_poller_handler[FelicaPollerStateNum] = { static const FelicaPollerReadHandler felica_poller_handler[FelicaPollerStateNum] = {
[FelicaPollerStateIdle] = felica_poller_state_handler_idle, [FelicaPollerStateIdle] = felica_poller_state_handler_idle,
[FelicaPollerStateActivated] = felica_poller_state_handler_activate, [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, [FelicaPollerStateAuthenticateInternal] = felica_poller_state_handler_auth_internal,
[FelicaPollerStateAuthenticateExternal] = felica_poller_state_handler_auth_external, [FelicaPollerStateAuthenticateExternal] = felica_poller_state_handler_auth_external,
[FelicaPollerStateTraverseStandardSystem] = [FelicaPollerStateTraverseStandardSystem] =

View File

@@ -233,8 +233,10 @@ static void felica_poller_prepare_tx_buffer_raw(
cmd.length = sizeof(FelicaCommandHeaderRaw) + data_length; cmd.length = sizeof(FelicaCommandHeaderRaw) + data_length;
bit_buffer_reset(instance->tx_buffer); bit_buffer_reset(instance->tx_buffer);
bit_buffer_append_bytes(instance->tx_buffer, (uint8_t*)&cmd, sizeof(FelicaCommandHeaderRaw)); bit_buffer_append_bytes(instance->tx_buffer, (uint8_t*)&cmd, sizeof(FelicaCommandHeaderRaw));
if(data_length > 0) {
bit_buffer_append_bytes(instance->tx_buffer, data, data_length); bit_buffer_append_bytes(instance->tx_buffer, data, data_length);
} }
}
FelicaError felica_poller_list_service_by_cursor( FelicaError felica_poller_list_service_by_cursor(
FelicaPoller* instance, FelicaPoller* instance,
@@ -264,3 +266,31 @@ FelicaError felica_poller_list_service_by_cursor(
*response_ptr = (FelicaListServiceCommandResponse*)bit_buffer_get_data(instance->rx_buffer); *response_ptr = (FelicaListServiceCommandResponse*)bit_buffer_get_data(instance->rx_buffer);
return error; return error;
} }
FelicaError felica_poller_list_system_code(
FelicaPoller* instance,
FelicaListSystemCodeCommandResponse** const response_ptr) {
furi_assert(instance);
furi_assert(response_ptr);
uint8_t data[] = {0};
felica_poller_prepare_tx_buffer_raw(instance, FELICA_CMD_REQUEST_SYSTEM_CODE, data, 0);
bit_buffer_reset(instance->rx_buffer);
FelicaError error = felica_poller_frame_exchange(
instance, instance->tx_buffer, instance->rx_buffer, FELICA_POLLER_POLLING_FWT);
if(error != FelicaErrorNone) {
FURI_LOG_E(TAG, "Request system code failed with error: %d", error);
return error;
}
size_t rx_len = bit_buffer_get_size_bytes(instance->rx_buffer);
if(rx_len < sizeof(FelicaCommandHeaderRaw) + 3) return FelicaErrorProtocol;
// at least 1 system code + the count being 0x01
// error is known to be FelicaErrorNone here
*response_ptr = (FelicaListSystemCodeCommandResponse*)bit_buffer_get_data(instance->rx_buffer);
return error;
}

View File

@@ -17,6 +17,8 @@ extern "C" {
typedef enum { typedef enum {
FelicaPollerStateIdle, FelicaPollerStateIdle,
FelicaPollerStateActivated, FelicaPollerStateActivated,
FelicaPollerStateListSystem,
FelicaPollerStateSelectSystemIndex,
FelicaPollerStateAuthenticateInternal, FelicaPollerStateAuthenticateInternal,
FelicaPollerStateAuthenticateExternal, FelicaPollerStateAuthenticateExternal,
FelicaPollerStateTraverseStandardSystem, FelicaPollerStateTraverseStandardSystem,
@@ -42,6 +44,8 @@ struct FelicaPoller {
FelicaPollerEventData felica_event_data; FelicaPollerEventData felica_event_data;
NfcGenericCallback callback; NfcGenericCallback callback;
uint8_t block_index; uint8_t block_index;
uint8_t systems_read;
uint8_t systems_total;
void* context; void* context;
}; };
@@ -116,6 +120,10 @@ FelicaError felica_poller_list_service_by_cursor(
uint16_t cursor, uint16_t cursor,
FelicaListServiceCommandResponse** response_ptr); FelicaListServiceCommandResponse** response_ptr);
FelicaError felica_poller_list_system_code(
FelicaPoller* instance,
FelicaListSystemCodeCommandResponse** response_ptr);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -135,6 +135,7 @@ Header,+,lib/nfc/helpers/iso14443_crc.h,,
Header,+,lib/nfc/helpers/nfc_data_generator.h,, Header,+,lib/nfc/helpers/nfc_data_generator.h,,
Header,+,lib/nfc/helpers/nfc_util.h,, Header,+,lib/nfc/helpers/nfc_util.h,,
Header,+,lib/nfc/nfc.h,, Header,+,lib/nfc/nfc.h,,
Header,+,lib/nfc/nfc_common.h,,
Header,+,lib/nfc/nfc_device.h,, Header,+,lib/nfc/nfc_device.h,,
Header,+,lib/nfc/nfc_listener.h,, Header,+,lib/nfc/nfc_listener.h,,
Header,+,lib/nfc/nfc_poller.h,, Header,+,lib/nfc/nfc_poller.h,,
@@ -636,8 +637,8 @@ Function,-,arc4random_uniform,__uint32_t,__uint32_t
Function,+,args_char_to_hex,_Bool,"char, char, uint8_t*" Function,+,args_char_to_hex,_Bool,"char, char, uint8_t*"
Function,+,args_get_first_word_length,size_t,FuriString* Function,+,args_get_first_word_length,size_t,FuriString*
Function,+,args_length,size_t,FuriString* Function,+,args_length,size_t,FuriString*
Function,+,args_read_float_and_trim,_Bool,"FuriString*, float*"
Function,+,args_read_duration,_Bool,"FuriString*, uint32_t*, const char*" Function,+,args_read_duration,_Bool,"FuriString*, uint32_t*, const char*"
Function,+,args_read_float_and_trim,_Bool,"FuriString*, float*"
Function,+,args_read_hex_bytes,_Bool,"FuriString*, uint8_t*, size_t" Function,+,args_read_hex_bytes,_Bool,"FuriString*, uint8_t*, size_t"
Function,+,args_read_int_and_trim,_Bool,"FuriString*, int*" Function,+,args_read_int_and_trim,_Bool,"FuriString*, int*"
Function,+,args_read_probably_quoted_string_and_trim,_Bool,"FuriString*, FuriString*" Function,+,args_read_probably_quoted_string_and_trim,_Bool,"FuriString*, FuriString*"
@@ -1119,7 +1120,7 @@ Function,+,felica_save,_Bool,"const FelicaData*, FlipperFormat*"
Function,+,felica_service_get_attribute_string,void,"const FelicaService*, FuriString*" Function,+,felica_service_get_attribute_string,void,"const FelicaService*, FuriString*"
Function,+,felica_set_uid,_Bool,"FelicaData*, const uint8_t*, size_t" Function,+,felica_set_uid,_Bool,"FelicaData*, const uint8_t*, size_t"
Function,+,felica_verify,_Bool,"FelicaData*, const FuriString*" Function,+,felica_verify,_Bool,"FelicaData*, const FuriString*"
Function,+,felica_write_directory_tree,void,"const FelicaData*, FuriString*" Function,+,felica_write_directory_tree,void,"const FelicaSystem*, FuriString*"
Function,-,feof,int,FILE* Function,-,feof,int,FILE*
Function,-,feof_unlocked,int,FILE* Function,-,feof_unlocked,int,FILE*
Function,-,ferror,int,FILE* Function,-,ferror,int,FILE*
1 entry status name type params
135 Header + lib/nfc/helpers/nfc_data_generator.h
136 Header + lib/nfc/helpers/nfc_util.h
137 Header + lib/nfc/nfc.h
138 Header + lib/nfc/nfc_common.h
139 Header + lib/nfc/nfc_device.h
140 Header + lib/nfc/nfc_listener.h
141 Header + lib/nfc/nfc_poller.h
637 Function + args_char_to_hex _Bool char, char, uint8_t*
638 Function + args_get_first_word_length size_t FuriString*
639 Function + args_length size_t FuriString*
Function + args_read_float_and_trim _Bool FuriString*, float*
640 Function + args_read_duration _Bool FuriString*, uint32_t*, const char*
641 Function + args_read_float_and_trim _Bool FuriString*, float*
642 Function + args_read_hex_bytes _Bool FuriString*, uint8_t*, size_t
643 Function + args_read_int_and_trim _Bool FuriString*, int*
644 Function + args_read_probably_quoted_string_and_trim _Bool FuriString*, FuriString*
1120 Function + felica_service_get_attribute_string void const FelicaService*, FuriString*
1121 Function + felica_set_uid _Bool FelicaData*, const uint8_t*, size_t
1122 Function + felica_verify _Bool FelicaData*, const FuriString*
1123 Function + felica_write_directory_tree void const FelicaData*, FuriString* const FelicaSystem*, FuriString*
1124 Function - feof int FILE*
1125 Function - feof_unlocked int FILE*
1126 Function - ferror int FILE*