diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index 0fd8e1e14..12be6ac09 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -45,7 +45,7 @@ static void nfc_cli_detect(Cli* cli, FuriString* args) { for(size_t i = 0; i < 8; i++) { printf("%02X", dev_data.uid[i]); } - printf("\r\nPMm:"); + printf(", PMm:"); for(size_t i = 0; i < 8; i++) { printf("%02X", dev_data.f_data.pmm[i]); } diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index a89d6c40b..c896a61ba 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -14,6 +14,8 @@ ADD_SCENE(nfc, file_select, FileSelect) ADD_SCENE(nfc, emulate_uid, EmulateUid) ADD_SCENE(nfc, nfca_read_success, NfcaReadSuccess) ADD_SCENE(nfc, nfca_menu, NfcaMenu) +ADD_SCENE(nfc, nfcf_read_success, NfcfReadSuccess) +ADD_SCENE(nfc, nfcf_menu, NfcfMenu) ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) ADD_SCENE(nfc, mf_ultralight_data, MfUltralightData) ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) diff --git a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c index 305b57ece..8f8391a64 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include void nfc_scene_nfc_data_info_widget_callback(GuiButtonType result, InputType type, void* context) { Nfc* nfc = context; @@ -11,6 +12,7 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { Nfc* nfc = context; Widget* widget = nfc->widget; FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; + FuriHalNfcType type = nfc_data->type; NfcDeviceData* dev_data = &nfc->dev->dev_data; NfcProtocol protocol = dev_data->protocol; uint8_t text_scroll_height = 0; @@ -40,20 +42,80 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { temp_str, "\e#%s\n", nfc_mf_classic_type(dev_data->mf_classic_data.type)); } else if(protocol == NfcDeviceProtocolMifareDesfire) { furi_string_cat_printf(temp_str, "\e#MIFARE DESfire\n"); + } else if(protocol == NfcDeviceProtocolFelica) { + furi_string_cat_printf(temp_str, "\e#%s\n", nfc_felica_type(dev_data->felica_data.type)); } else { furi_string_cat_printf(temp_str, "\e#Unknown ISO tag\n"); } - // Set tag iso data - char iso_type = FURI_BIT(nfc_data->a_data.sak, 5) ? '4' : '3'; - furi_string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type); - furi_string_cat_printf(temp_str, "UID:"); - for(size_t i = 0; i < nfc_data->uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + // Set tag general data + if(type == FuriHalNfcTypeF) { + // Set NFC-F data + furi_string_cat_printf(temp_str, "ISO 18092 (NFC-F)\n"); + furi_string_cat_printf(temp_str, "CIN:"); + // NFC-F Card Identification Number (CIN) starts at "UID" byte 2. + for(size_t i = 2; i < nfc_data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + } + // The first 2 bytes of the "UID" are Manufacturer Code (MC) + furi_string_cat_printf( + temp_str, + "\nMC: %02X %02X ROM: %02X IC: %02X\n\n", + nfc_data->uid[0], + nfc_data->uid[1], + nfc_data->f_data.pmm[0], + nfc_data->f_data.pmm[1]); + + furi_string_cat_printf(temp_str, "Timings (1 node/blk):\n"); + furi_string_cat_printf( + temp_str, + "- ReqSvc: %" PRIuLEAST32 "us\n", + felica_estimate_timing_us(nfc_data->f_data.pmm[2], 1)); + furi_string_cat_printf( + temp_str, + "- Fixed: %" PRIuLEAST32 "us\n", + felica_estimate_timing_us(nfc_data->f_data.pmm[3], 0)); + furi_string_cat_printf( + temp_str, + "- Auth1: %" PRIuLEAST32 "us\n", + felica_estimate_timing_us(nfc_data->f_data.pmm[4], 1)); + furi_string_cat_printf( + temp_str, + "- Auth2: %" PRIuLEAST32 "us\n", + felica_estimate_timing_us(nfc_data->f_data.pmm[4], 0)); + furi_string_cat_printf( + temp_str, + "- Read: %" PRIuLEAST32 "us\n", + felica_estimate_timing_us(nfc_data->f_data.pmm[5], 1)); + furi_string_cat_printf( + temp_str, + "- Write: %" PRIuLEAST32 "us\n", + felica_estimate_timing_us(nfc_data->f_data.pmm[6], 1)); + furi_string_cat_printf( + temp_str, + "- Other: %" PRIuLEAST32 "us\n\n", + felica_estimate_timing_us(nfc_data->f_data.pmm[7], 0)); + + furi_string_cat_printf(temp_str, "IDm:"); + for(size_t i = 0; i < nfc_data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + } + furi_string_cat_printf(temp_str, "\nPMm:"); + for(size_t i = 0; i < sizeof(nfc_data->f_data.pmm); i++) { + furi_string_cat_printf(temp_str, " %02X", nfc_data->f_data.pmm[i]); + } + } else { // FuriHalNfcTypeA + // Set tag iso data + char iso_type = FURI_BIT(nfc_data->a_data.sak, 5) ? '4' : '3'; + furi_string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type); + furi_string_cat_printf(temp_str, "UID:"); + for(size_t i = 0; i < nfc_data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + } + furi_string_cat_printf( + temp_str, "\nATQA: %02X %02X ", nfc_data->a_data.atqa[1], nfc_data->a_data.atqa[0]); + furi_string_cat_printf(temp_str, " SAK: %02X", nfc_data->a_data.sak); } - furi_string_cat_printf( - temp_str, "\nATQA: %02X %02X ", nfc_data->a_data.atqa[1], nfc_data->a_data.atqa[0]); - furi_string_cat_printf(temp_str, " SAK: %02X", nfc_data->a_data.sak); // Set application specific data if(protocol == NfcDeviceProtocolMifareDesfire) { diff --git a/applications/main/nfc/scenes/nfc_scene_nfcf_menu.c b/applications/main/nfc/scenes/nfc_scene_nfcf_menu.c new file mode 100644 index 000000000..cae7055b1 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_nfcf_menu.c @@ -0,0 +1,80 @@ +#include "../nfc_i.h" +#include + +enum SubmenuIndex { + /* + SubmenuIndexSave, + SubmenuIndexEmulate, + */ + SubmenuIndexInfo, +}; + +void nfc_scene_nfcf_menu_submenu_callback(void* context, uint32_t index) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_nfcf_menu_on_enter(void* context) { + Nfc* nfc = context; + Submenu* submenu = nfc->submenu; + // FelicaData* data = &nfc->dev->dev_data.felica_data; + + /* + submenu_add_item( + submenu, "Save IDm", SubmenuIndexSave, nfc_scene_felica_menu_submenu_callback, nfc); + submenu_add_item( + submenu, "Emulate IDm", SubmenuIndexEmulate, nfc_scene_felica_menu_submenu_callback, nfc); + */ + submenu_add_item(submenu, "Info", SubmenuIndexInfo, nfc_scene_nfcf_menu_submenu_callback, nfc); + + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcfMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_nfcf_menu_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + /* + if(event.event == SubmenuIndexSave) { + nfc->dev->format = NfcDeviceSaveFormatFelica; + // Clear device name + nfc_device_set_name(nfc->dev, ""); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + consumed = true; + } else if(event.event == SubmenuIndexEmulate) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaEmulate); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + } else { + DOLPHIN_DEED(DolphinDeedNfcEmulate); + } + consumed = true; + } else if(event.event == SubmenuIndexUnlock) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaUnlockMenu); + consumed = true; + } else + */ + if(event.event == SubmenuIndexInfo) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + consumed = true; + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcfMenu, event.event); + + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + + return consumed; +} + +void nfc_scene_nfcf_menu_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc/scenes/nfc_scene_nfcf_read_success.c b/applications/main/nfc/scenes/nfc_scene_nfcf_read_success.c new file mode 100644 index 000000000..da695ba83 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_nfcf_read_success.c @@ -0,0 +1,88 @@ +#include "../nfc_i.h" +#include "nfc_device.h" + +void nfc_scene_nfcf_read_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + furi_assert(context); + Nfc* nfc = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_nfcf_read_success_on_enter(void* context) { + Nfc* nfc = context; + + FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; + NfcDeviceData* dev_data = &nfc->dev->dev_data; + + // Setup view + Widget* widget = nfc->widget; + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_scene_nfcf_read_success_widget_callback, nfc); + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_scene_nfcf_read_success_widget_callback, nfc); + + FuriString* temp_str = furi_string_alloc(); + + if(dev_data->protocol == NfcDeviceProtocolFelica) { + furi_string_cat_printf(temp_str, "\e#%s", nfc_felica_type(dev_data->felica_data.type)); + } else { + furi_string_cat_printf(temp_str, "\e#Unknown ISO tag"); + } + + furi_string_cat_printf(temp_str, "\nISO 18092 (NFC-F)"); + + furi_string_cat_printf(temp_str, "\nCIN:"); + // NFC-F Card Identification Number (CIN) starts at "UID" byte 2. + for(size_t i = 2; i < data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", data->uid[i]); + } + + // The first 2 bytes of the "UID" are Manufacturer Code (MC) + furi_string_cat_printf( + temp_str, + "\nMC: %02X %02X ROM: %02X IC: %02X", + data->uid[0], + data->uid[1], + data->f_data.pmm[0], + data->f_data.pmm[1]); + + widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + notification_message_block(nfc->notifications, &sequence_set_green_255); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_nfcf_read_success_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); + consumed = true; + } else if(event.event == GuiButtonTypeRight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcfMenu); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + return consumed; +} + +void nfc_scene_nfcf_read_success_on_exit(void* context) { + Nfc* nfc = context; + + notification_message_block(nfc->notifications, &sequence_reset_green); + + // Clear view + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index a4d7be2c3..40645c353 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -57,7 +57,6 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if((event.event == NfcWorkerEventReadUidNfcB) || - (event.event == NfcWorkerEventReadUidNfcF) || (event.event == NfcWorkerEventReadUidNfcV)) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); @@ -97,6 +96,11 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); } consumed = true; + } else if(event.event == NfcWorkerEventReadUidNfcF) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcfReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + consumed = true; } else if(event.event == NfcWorkerEventReadFelica) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaReadSuccess); diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 4da897958..935f0eca8 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,11.10,, +Version,+,11.13,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -803,6 +803,7 @@ Function,-,fdopen,FILE*,"int, const char*" Function,-,felica_check_ic_type,_Bool,uint8_t* Function,-,felica_clear,void,FelicaData* Function,-,felica_define_normal_block,void,"FelicaService*, uint16_t, uint8_t*" +Function,-,felica_estimate_timing_us,uint_least32_t,"uint_least8_t, uint_least8_t" Function,-,felica_get_ic_type,FelicaICType,uint8_t* Function,-,felica_get_service_name,FuriString*,FelicaService* Function,-,felica_get_system_name,FuriString*,FelicaSystem* diff --git a/lib/nfc/protocols/felica.c b/lib/nfc/protocols/felica.c index d9489cb50..b3405cf6b 100644 --- a/lib/nfc/protocols/felica.c +++ b/lib/nfc/protocols/felica.c @@ -8,13 +8,15 @@ #define TAG "FeliCa" bool felica_check_ic_type(uint8_t* PMm) { - uint8_t ic_type = PMm[0]; - uint8_t rom_type = PMm[1]; + uint8_t rom_type = PMm[0]; + uint8_t ic_type = PMm[1]; bool is_valid_ic = false; if(ic_type == 0xff) { // RC-S967 in nfc-dep is_valid_ic = true; - } else if(ic_type == 0xf0 || ic_type == 0xf2) { // Lite(S) + } else if(ic_type == 0xf2) { // RC-S732? + is_valid_ic = true; + } else if(ic_type == 0xf0 || ic_type == 0xf1) { // Lite(S) is_valid_ic = true; } else if(ic_type == 0xe1) { // RC-S967 in plug mode is_valid_ic = true; diff --git a/lib/nfc/protocols/felica_util.c b/lib/nfc/protocols/felica_util.c index a5198aa09..aba13c4be 100644 --- a/lib/nfc/protocols/felica_util.c +++ b/lib/nfc/protocols/felica_util.c @@ -1,6 +1,15 @@ #include "./felica.h" #include +static const uint32_t TIME_CONSTANT_US = 302; + +uint_least32_t felica_estimate_timing_us(uint_least8_t timing, uint_least8_t units) { + uint_least32_t base_cost_factor = 1 + (timing & 0x7); + uint_least32_t unit_cost_factor = 1 + ((timing >> 3) & 0x7); + uint_least32_t scale = 1 << ((timing >> 6) * 2); + return TIME_CONSTANT_US * scale * (base_cost_factor + unit_cost_factor * units); +} + FuriString* felica_get_system_name(FelicaSystem* system) { uint16_t code = system->code; diff --git a/lib/nfc/protocols/felica_util.h b/lib/nfc/protocols/felica_util.h index 4224668eb..e53d66805 100644 --- a/lib/nfc/protocols/felica_util.h +++ b/lib/nfc/protocols/felica_util.h @@ -1,4 +1,5 @@ #include "./felica.h" +uint_least32_t felica_estimate_timing_us(uint_least8_t timing, uint_least8_t units); FuriString* felica_get_system_name(FelicaSystem* system); FuriString* felica_get_service_name(FelicaService* service); \ No newline at end of file